1 // Created on: 1995-06-27
2 // Created by: Jacques GOUSSARD
3 // Copyright (c) 1995-1999 Matra Datavision
4 // Copyright (c) 1999-2014 OPEN CASCADE SAS
6 // This file is part of Open CASCADE Technology software library.
8 // This library is free software; you can redistribute it and/or modify it under
9 // the terms of the GNU Lesser General Public License version 2.1 as published
10 // by the Free Software Foundation, with special exception defined in the file
11 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
12 // distribution for complete text of the license and disclaimer of any warranty.
14 // Alternatively, this file may be used under the terms of Open CASCADE
15 // commercial license or contractual agreement.
17 #include <LocOpe_SplitShape.ixx>
18 #include <TopTools_IndexedMapOfShape.hxx>
19 #include <TopTools_ListOfShape.hxx>
20 #include <TopTools_ListIteratorOfListOfShape.hxx>
21 #include <TopTools_MapOfShape.hxx>
22 #include <TopTools_MapOfOrientedShape.hxx>
23 #include <TopTools_DataMapOfShapeListOfShape.hxx>
24 #include <TopTools_DataMapIteratorOfDataMapOfShapeListOfShape.hxx>
25 #include <TopTools_DataMapOfShapeInteger.hxx>
26 #include <TopTools_DataMapOfShapeShape.hxx>
27 #include <TopTools_DataMapIteratorOfDataMapOfShapeShape.hxx>
28 #include <TopTools_MapIteratorOfMapOfShape.hxx>
29 #include <TopTools_MapIteratorOfMapOfOrientedShape.hxx>
30 #include <TopoDS_Iterator.hxx>
31 #include <TopExp_Explorer.hxx>
32 #include <BRep_Builder.hxx>
33 #include <TopoDS_Vertex.hxx>
34 #include <BRepLib_MakeFace.hxx>
35 #include <BRepLib_MakeWire.hxx>
36 #include <BRep_Tool.hxx>
37 #include <BRepTools.hxx>
38 #include <BRepTools_WireExplorer.hxx>
39 #include <BRep_Builder.hxx>
41 #include <BRepClass_FaceExplorer.hxx>
42 #include <BRepTopAdaptor_FClass2d.hxx>
43 #include <BRepAdaptor_Surface.hxx>
45 #include <Geom2d_Curve.hxx>
46 #include <gp_Pnt2d.hxx>
47 #include <gp_Vec2d.hxx>
48 #include <gp_Dir2d.hxx>
51 #include <Precision.hxx>
52 #include <BRepTools.hxx>
54 #include <Standard_ErrorHandler.hxx>
56 static Standard_Boolean IsInside(const TopoDS_Face&,
60 static Standard_Boolean IsInside(const TopoDS_Face&,
63 static void GetDirection(const TopoDS_Edge&,
69 static void ChoixUV(const TopoDS_Edge&,
71 const TopTools_IndexedMapOfShape&,
75 const Standard_Real tol);
77 static TopoDS_Shape ChooseDirection(const TopoDS_Shape&,
80 const TopTools_ListOfShape&);
82 inline Standard_Boolean SameUV(const gp_Pnt2d& P1, const gp_Pnt2d& P2,
83 const BRepAdaptor_Surface& theBAS)//const Standard_Real tol)
85 // Standard_Real tol = Precision::Confusion();
86 // return P1.SquareDistance(P2) < 10*tol;
88 Standard_Boolean isSame = Standard_True;
89 if(theBAS.IsUPeriodic())
90 isSame = (fabs(P1.X() - P2.X()) < theBAS.UPeriod() *0.5);
91 if(theBAS.IsVPeriodic())
92 isSame = (isSame && (fabs(P1.Y() - P2.Y()) < theBAS.VPeriod() *0.5));
94 //return P1.SquareDistance(P2) < tol * tol; //IFV
99 //=======================================================================
102 //=======================================================================
104 void LocOpe_SplitShape::Init(const TopoDS_Shape& S)
106 myDone = Standard_False;
114 //=======================================================================
115 //function : CanSplit
117 //=======================================================================
119 Standard_Boolean LocOpe_SplitShape::CanSplit(const TopoDS_Edge& E) const
122 return Standard_False;
124 if (myMap.IsEmpty()) {
125 return Standard_False;
128 if (!myMap.IsBound(E)) {
129 return Standard_False;
132 // On verifie que l`edge n`appartient pas a un wire deja reconstruit
134 TopTools_DataMapIteratorOfDataMapOfShapeListOfShape itm(myMap);
135 for (; itm.More(); itm.Next()) {
136 if (itm.Key().ShapeType() == TopAbs_WIRE && !itm.Value().IsEmpty()) {
137 for (exp.Init(itm.Key(),TopAbs_EDGE); exp.More(); exp.Next()) {
138 if (exp.Current().IsSame(E)) {
139 return Standard_False;
144 return Standard_True;
148 //=======================================================================
151 //=======================================================================
153 void LocOpe_SplitShape::Add(const TopoDS_Vertex& V,
154 const Standard_Real P,
155 const TopoDS_Edge& E)
158 Standard_ConstructionError::Raise();
162 TopTools_ListOfShape& le = myMap(E);
166 TopTools_ListIteratorOfListOfShape itl(le);
169 for (; itl.More(); itl.Next()) {
170 const TopoDS_Edge& edg = TopoDS::Edge(itl.Value());
171 BRep_Tool::Range(edg,f,l);
177 Standard_ConstructionError::Raise();
179 TopoDS_Edge edg = TopoDS::Edge(itl.Value());
181 if (V.Orientation() == TopAbs_FORWARD ||
182 V.Orientation() == TopAbs_REVERSED) {
184 TopoDS_Shape aLocalShape = edg.EmptyCopied();
185 TopoDS_Edge E1 = TopoDS::Edge(aLocalShape);
186 aLocalShape = edg.EmptyCopied();
187 TopoDS_Edge E2 = TopoDS::Edge(aLocalShape);
188 // TopoDS_Edge E1 = TopoDS::Edge(edg.EmptyCopied());
189 // TopoDS_Edge E2 = TopoDS::Edge(edg.EmptyCopied());
190 E1.Orientation(TopAbs_FORWARD);
191 E2.Orientation(TopAbs_FORWARD);
192 TopoDS_Vertex newVtx = V;
193 newVtx.Orientation(TopAbs_REVERSED);
195 B.UpdateVertex(newVtx,P,E1,BRep_Tool::Tolerance(V));
196 newVtx.Orientation(TopAbs_FORWARD);
198 B.UpdateVertex(newVtx,P,E2,BRep_Tool::Tolerance(V));
199 edg.Orientation(TopAbs_FORWARD);
201 for (exp.Init(edg,TopAbs_VERTEX); exp.More(); exp.Next()) {
202 // for (TopExp_Explorer exp(edg,TopAbs_VERTEX); exp.More(); exp.Next()) {
203 const TopoDS_Vertex& vtx = TopoDS::Vertex(exp.Current());
204 f = BRep_Tool::Parameter(vtx,edg);
207 B.UpdateVertex(vtx,f,E1,BRep_Tool::Tolerance(vtx));
211 B.UpdateVertex(vtx,f,E2,BRep_Tool::Tolerance(vtx));
218 TopoDS_Shape aLocalShape = edg.EmptyCopied();
219 TopoDS_Edge E1 = TopoDS::Edge(aLocalShape);
220 // TopoDS_Edge E1 = TopoDS::Edge(edg.EmptyCopied());
222 for (exp.Init(edg,TopAbs_VERTEX); exp.More(); exp.Next()) {
223 // for (TopExp_Explorer exp(edg,TopAbs_VERTEX); exp.More(); exp.Next()) {
224 const TopoDS_Vertex& vtx = TopoDS::Vertex(exp.Current());
225 f = BRep_Tool::Parameter(vtx,edg);
227 B.UpdateVertex(vtx,f,E1,BRep_Tool::Tolerance(vtx));
230 B.UpdateVertex(V,P,E1,BRep_Tool::Tolerance(V));
235 //=======================================================================
237 //purpose : adds the list of wires on the face <F>
238 //=======================================================================
240 void LocOpe_SplitShape::Add(const TopTools_ListOfShape& Lwires,
241 const TopoDS_Face& F)
245 Standard_ConstructionError::Raise();
248 TopTools_ListOfShape& lf = myMap(F);
253 // On cherche la face descendante de F qui continent le wire
255 TopTools_ListIteratorOfListOfShape itl(lf);
256 TopoDS_Vertex Vfirst,Vlast;
258 BRepTools::Update(F);
260 for (; itl.More(); itl.Next())
262 const TopoDS_Face& fac = TopoDS::Face(itl.Value());
263 Standard_Boolean AllWiresInside = Standard_True;
264 TopTools_ListIteratorOfListOfShape itwires(Lwires);
265 for (; itwires.More(); itwires.Next())
267 const TopoDS_Wire& aWire = TopoDS::Wire(itwires.Value());
268 if (!IsInside(fac, aWire))
270 AllWiresInside = Standard_False;
278 Standard_ConstructionError::Raise();
281 TopoDS_Face FaceRef = TopoDS::Face(itl.Value());
282 FaceRef.Orientation(TopAbs_FORWARD);
285 TopTools_ListOfShape NewWires;
287 TopTools_DataMapOfShapeInteger SectionsTimes;
288 for (itl.Initialize(Lwires); itl.More(); itl.Next())
289 SectionsTimes.Bind(itl.Value(), 2);
291 TopTools_ListOfShape BreakVertices;
292 TopTools_ListOfShape BreakOnWires;
294 TopTools_DataMapOfShapeShape VerWireMap;
296 TopExp_Explorer ExploF, ExploW;
297 for (itl.Initialize(Lwires); itl.More(); itl.Next())
299 const TopoDS_Wire& aSection = TopoDS::Wire(itl.Value());
300 TopoDS_Vertex Ver [2];
301 TopExp::Vertices(aSection, Ver[0], Ver[1]);
302 for (i = 0; i < 2; i++)
304 if (VerWireMap.IsBound(Ver[i]))
306 for (ExploF.Init(FaceRef, TopAbs_WIRE); ExploF.More(); ExploF.Next())
308 const TopoDS_Shape& aWire = ExploF.Current();
310 for (ExploW.Init(aWire, TopAbs_VERTEX); ExploW.More(); ExploW.Next())
312 aVer = ExploW.Current();
313 if (aVer.IsSame(Ver[i]))
316 if (aVer.IsSame(Ver[i]))
318 VerWireMap.Bind(aVer, aWire);
325 TopTools_DataMapOfShapeListOfShape VerSecMap;
326 for (itl.Initialize(Lwires); itl.More(); itl.Next())
328 const TopoDS_Wire& aWire = TopoDS::Wire(itl.Value());
329 TopoDS_Vertex V1, V2;
330 TopExp::Vertices(aWire, V1, V2);
331 TopTools_ListOfShape LW1, LW2;
332 if (!VerSecMap.IsBound(V1))
333 VerSecMap.Bind(V1, LW1);
334 VerSecMap(V1).Append(aWire);
335 if (!VerSecMap.IsBound(V2))
336 VerSecMap.Bind(V2, LW2);
337 VerSecMap(V2).Append(aWire);
340 //TopTools_IndexedDataMapOfShapeShape InnerTouchingWiresOnVertex;
342 TopoDS_Wire outerW = BRepTools::OuterWire(FaceRef);
343 TopoDS_Wire CurWire = outerW;
344 BRepLib_MakeWire *MW;
345 MW = new BRepLib_MakeWire();
346 BRepTools_WireExplorer wexp(CurWire, FaceRef);
349 TopoDS_Vertex theStartVertex = wexp.CurrentVertex(), CurVertex;
350 TopoDS_Edge CurEdge = wexp.Current();
351 TopoDS_Edge LastEdge = CurEdge;
353 TopoDS_Wire aSectionWire;
354 TopoDS_Vertex aBreakVertex;
357 wexp.Init(CurWire, FaceRef);
360 if (MW->Wire().Closed())
362 CurVertex = wexp.CurrentVertex();
363 if (VerSecMap.IsBound(CurVertex))
365 TopoDS_Shape aLocalWire = ChooseDirection(LastEdge, CurVertex, FaceRef, VerSecMap(CurVertex));
366 aSectionWire = TopoDS::Wire(aLocalWire);
369 CurEdge = wexp.Current();
374 wexp.Init(CurWire, FaceRef);
376 if (MW->Wire().Closed())
378 NewWires.Append(MW->Wire());
379 theStartVertex = TopoDS::Vertex(BreakVertices.First());
380 BreakVertices.RemoveFirst();
381 CurWire = TopoDS::Wire(BreakOnWires.First());
382 BreakOnWires.RemoveFirst();
383 wexp.Init(CurWire, FaceRef);
384 while (!wexp.CurrentVertex().IsSame(theStartVertex))
386 MW = new BRepLib_MakeWire();
389 aBreakVertex = CurVertex;
390 BreakVertices.Append(aBreakVertex);
391 BreakOnWires.Append(CurWire);
394 MW->Add(aSectionWire);
395 (SectionsTimes(aSectionWire))--;
396 if (SectionsTimes(aSectionWire) == 0)
397 SectionsTimes.UnBind(aSectionWire);
398 if (MW->Wire().Closed())
400 NewWires.Append(MW->Wire());
401 if (SectionsTimes.IsEmpty())
403 theStartVertex = TopoDS::Vertex(BreakVertices.First());
404 BreakVertices.RemoveFirst();
405 CurWire = TopoDS::Wire(BreakOnWires.First());
406 BreakOnWires.RemoveFirst();
407 wexp.Init(CurWire, FaceRef);
408 while (!wexp.CurrentVertex().IsSame(theStartVertex))
410 MW = new BRepLib_MakeWire();
415 TopoDS_Vertex V1, V2, aStartVertex;
416 TopExp::Vertices(aSectionWire, V1, V2);
417 aStartVertex = (V1.IsSame(aBreakVertex))? V2 : V1;
418 CurWire = TopoDS::Wire(VerWireMap(aStartVertex));
420 wexp.Init(CurWire, FaceRef);
421 while (!wexp.CurrentVertex().IsSame(aStartVertex))
424 const TopTools_ListOfShape& Lsections = VerSecMap(aStartVertex);
425 if (Lsections.Extent() == 1)
428 //else: choose the way
429 TopoDS_Wire NextSectionWire =
430 TopoDS::Wire((aSectionWire.IsSame(Lsections.First()))? Lsections.Last() : Lsections.First());
432 Standard_Integer Times = 0;
433 TopTools_DataMapIteratorOfDataMapOfShapeShape itVW(VerWireMap);
434 for (; itVW.More(); itVW.Next())
435 if (itVW.Value().IsSame(CurWire))
437 if (Times == 1) //it is inner touching wire
439 //InnerTouchingWiresOnVertex.Bind(aWire, aStartVertex);
443 //we have to choose the direction
444 TopoDS_Edge aStartEdge = wexp.Current();
445 TopTools_ListOfShape Ldirs;
446 Ldirs.Append(aStartEdge);
447 Ldirs.Append(NextSectionWire);
448 TopoDS_Shape theDirection = ChooseDirection(aSectionWire, aStartVertex, FaceRef, Ldirs);
449 if (theDirection.IsSame(aStartEdge))
452 aSectionWire = NextSectionWire;
453 aBreakVertex = aStartVertex;
454 } //end of else (MW is not closed)
455 } //end of for (;;) (loop on section wires)
456 if (SectionsTimes.IsEmpty())
458 } //end of global for (;;)
460 TopTools_ListOfShape NewFaces;
462 for (itl.Initialize(NewWires); itl.More(); itl.Next())
464 TopoDS_Shape aLocalFace = FaceRef.EmptyCopied();
465 TopoDS_Face aNewFace = TopoDS::Face(aLocalFace);
466 aNewFace.Orientation(TopAbs_FORWARD);
467 BB.Add(aNewFace, itl.Value());
468 NewFaces.Append(aNewFace);
472 TopTools_ListOfShape Holes;
473 for (ExploF.Init(FaceRef, TopAbs_WIRE); ExploF.More(); ExploF.Next())
475 const TopoDS_Shape& aWire = ExploF.Current();
476 ExploW.Init(aWire, TopAbs_EDGE);
477 TopoDS_Shape anEdge = ExploW.Current();
478 Standard_Boolean found = Standard_False;
479 for (itl.Initialize(NewWires); itl.More(); itl.Next())
481 const TopoDS_Shape& aNewWire = itl.Value();
482 for (ExploW.Init(aNewWire, TopAbs_EDGE); ExploW.More(); ExploW.Next())
484 if (anEdge.IsSame(ExploW.Current()))
486 found = Standard_True;
496 TopTools_ListIteratorOfListOfShape itlNewF;
497 for (itl.Initialize(Holes); itl.More(); itl.Next())
499 const TopoDS_Wire& aHole = TopoDS::Wire(itl.Value());
500 for (itlNewF.Initialize(NewFaces); itlNewF.More(); itlNewF.Next())
502 TopoDS_Face& aNewFace = TopoDS::Face(itlNewF.Value());
503 if (IsInside(aNewFace, aHole))
505 BB.Add(aNewFace, aHole);
514 //Update of descendants of wires
515 for (ExploF.Init(F, TopAbs_WIRE); ExploF.More(); ExploF.Next())
517 TopTools_ListOfShape& ls = myMap(ExploF.Current());
522 // JAG 10.11.95 Codage des regularites
523 for (itl.Initialize(Lwires); itl.More(); itl.Next())
524 for (ExploW.Init(itl.Value(), TopAbs_EDGE); ExploW.More(); ExploW.Next())
526 const TopoDS_Edge& edg = TopoDS::Edge(ExploW.Current());
527 if (!BRep_Tool::HasContinuity(edg,F,F)) {
528 BB.Continuity(edg,F,F,GeomAbs_CN);
534 //=======================================================================
537 //=======================================================================
539 void LocOpe_SplitShape::Add(const TopoDS_Wire& W,
540 const TopoDS_Face& F)
544 Standard_ConstructionError::Raise();
549 TopTools_ListOfShape& lf = myMap(F);
555 if (!LocOpe::Closed(W,F)) {
561 } catch (Standard_Failure ) {
563 cout << "Warning: SpliShape internal problem detected, some faces may be lost. Check input edges/wires" <<endl;
567 // JAG 10.11.95 Codage des regularites
569 for (exp.Init(W,TopAbs_EDGE); exp.More(); exp.Next()) {
570 const TopoDS_Edge& edg = TopoDS::Edge(exp.Current());
571 if (!BRep_Tool::HasContinuity(edg,F,F)) {
572 B.Continuity(edg,F,F,GeomAbs_CN);
579 //=======================================================================
580 //function : AddClosedWire
582 //=======================================================================
584 void LocOpe_SplitShape::AddClosedWire(const TopoDS_Wire& W,
585 const TopoDS_Face& F)
589 // On cherche la face descendante de F qui continent le wire
590 TopTools_ListOfShape& lf = myMap(F);
591 TopTools_ListIteratorOfListOfShape itl(lf);
593 for (; itl.More(); itl.Next()) {
594 const TopoDS_Face& fac = TopoDS::Face(itl.Value());
596 outerW = BRepTools::OuterWire(fac);
597 if (IsInside(F,W,outerW)) {
601 if (IsInside(fac,W)) {
607 Standard_ConstructionError::Raise();
612 TopAbs_Orientation orWire = W.Orientation();
613 TopoDS_Shape aLocalFace = F.EmptyCopied();
614 TopoDS_Face newFace = TopoDS::Face(aLocalFace);
615 // TopoDS_Face newFace = TopoDS::Face(F.EmptyCopied());
616 newFace.Orientation(TopAbs_FORWARD);
619 // BRepGProp::SurfaceProperties (newFace,GP);
620 // if (GP.Mass() < 0) {
621 BRepTopAdaptor_FClass2d classif(newFace,Precision::PConfusion());
622 if (classif.PerformInfinitePoint() == TopAbs_IN) {
623 //le wire donne defini un trou
624 aLocalFace = F.EmptyCopied();
625 newFace = TopoDS::Face(aLocalFace);
626 // newFace = TopoDS::Face(F.EmptyCopied());
627 newFace.Orientation(TopAbs_FORWARD);
628 orWire = TopAbs::Reverse(orWire);
629 B.Add(newFace,W.Oriented(orWire));
632 TopoDS_Face FaceRef = TopoDS::Face(itl.Value());
633 FaceRef.Orientation(TopAbs_FORWARD);
636 aLocalFace = FaceRef.EmptyCopied();
637 TopoDS_Face newRef = TopoDS::Face(aLocalFace);
638 // TopoDS_Face newRef = TopoDS::Face(FaceRef.EmptyCopied());
639 newRef.Orientation(TopAbs_FORWARD);
641 // On suppose que les edges du wire ont des courbes 2d.
642 // Comme on ne change pas de surface de base, pas besoin d`UpdateEdge.
644 for (exp.Init(FaceRef.Oriented(TopAbs_FORWARD),TopAbs_WIRE);
645 exp.More(); exp.Next()) {
646 const TopoDS_Wire& wir = TopoDS::Wire(exp.Current());
647 if (IsInside(F,wir,W)) {
654 B.Add(newRef,W.Oriented(TopAbs::Reverse(orWire)));
661 //=======================================================================
662 //function : AddOpenWire
664 //=======================================================================
666 void LocOpe_SplitShape::AddOpenWire(const TopoDS_Wire& W,
667 const TopoDS_Face& F)
669 // On cherche la face descendante de F qui continent le wire
670 TopTools_ListOfShape& lf = myMap(F);
671 TopTools_ListIteratorOfListOfShape itl(lf);
672 TopoDS_Vertex Vfirst,Vlast;
674 BRepTools::Update(F);
676 Standard_Real tolf, toll, tol1;
678 TopoDS_Shape aLocalShape = W.Oriented(TopAbs_FORWARD);
679 TopExp::Vertices(TopoDS::Wire(aLocalShape),Vfirst,Vlast);
681 tolf = BRep_Tool::Tolerance(Vfirst);
682 toll = BRep_Tool::Tolerance(Vlast);
683 tol1 = Max(tolf, toll);
686 TopExp_Explorer exp,exp2;
688 TopoDS_Wire wfirst,wlast;
689 for (; itl.More(); itl.Next()) {
690 TopoDS_Face fac = TopoDS::Face(itl.Value());
691 if (!IsInside(fac,W)) {
695 fac.Orientation(TopAbs_FORWARD);
696 Standard_Boolean ffound = Standard_False;
697 Standard_Boolean lfound = Standard_False;
698 for (exp.Init(fac,TopAbs_WIRE); exp.More(); exp.Next()) {
699 const TopoDS_Wire& wir = TopoDS::Wire(exp.Current());
700 for (exp2.Init(wir,TopAbs_VERTEX); exp2.More(); exp2.Next()) {
701 if (!ffound && exp2.Current().IsSame(Vfirst)) {
702 ffound = Standard_True;
705 else if (!lfound && exp2.Current().IsSame(Vlast)) {
706 lfound = Standard_True;
709 if (ffound && lfound) {
722 Standard_ConstructionError::Raise();
725 TopoDS_Face FaceRef = TopoDS::Face(itl.Value());
726 FaceRef.Orientation(TopAbs_FORWARD);
730 BRepAdaptor_Surface BAS(FaceRef, Standard_False);
732 Standard_Boolean IsPeriodic = BAS.IsUPeriodic() || BAS.IsVPeriodic();
734 tol1 = Max(BAS.UResolution(tol1), BAS.VResolution(tol1));
736 if (wfirst.IsSame(wlast)) {
737 // on cree 2 faces en remplacement de itl.Value()
739 TopTools_ListOfShape WiresFirst;
740 for (exp.Init(wfirst,TopAbs_EDGE); exp.More(); exp.Next()) {
741 if (BRep_Tool::IsClosed(TopoDS::Edge(exp.Current()),FaceRef)) {
742 myDblE.Add(exp.Current());
744 WiresFirst.Append(exp.Current());
747 TopAbs_Orientation orient;
748 TopoDS_Wire newW1,newW2;
750 newW1.Orientation(TopAbs_FORWARD);
752 newW2.Orientation(TopAbs_FORWARD);
754 Standard_Integer nbE = 0;
755 for (exp.Init(W.Oriented(TopAbs_FORWARD),TopAbs_EDGE);
756 exp.More(); exp.Next()) {
758 const TopoDS_Edge& edg = TopoDS::Edge(exp.Current());
759 orient = edg.Orientation();
760 WiresFirst.Append(edg);
761 WiresFirst.Append(edg.Oriented(TopAbs::Reverse(orient)));
765 TopTools_IndexedMapOfShape PossE;
766 TopTools_MapOfOrientedShape MapE;
767 TopoDS_Vertex vdeb,vfin;
768 Standard_Integer nbPoss;
770 // On recherche l`edge contenant Vlast
771 TopoDS_Edge LastEdge;
772 gp_Pnt2d pfirst,plast;
774 Handle(Geom2d_Curve) C2d;
777 for (exp.Init(W.Oriented(TopAbs_FORWARD),TopAbs_EDGE);
778 exp.More(); exp.Next()) {
779 const TopoDS_Edge& edg = TopoDS::Edge(exp.Current());
780 for (exp2.Init(edg,TopAbs_VERTEX); exp2.More(); exp2.Next()) {
781 if (exp2.Current().IsSame(Vfirst)) {
787 LastEdge.Orientation(edg.Orientation());
792 TopoDS_Shape aLocalFace = FaceRef.Oriented(wfirst.Orientation());
793 C2d = BRep_Tool::CurveOnSurface(LastEdge, TopoDS::Face(aLocalFace), f, l);
795 if (LastEdge.Orientation() == TopAbs_FORWARD) {
796 pfirst = C2d->Value(f);
799 pfirst = C2d->Value(l);
802 for (exp.Init(W.Oriented(TopAbs_FORWARD),TopAbs_EDGE);
803 exp.More(); exp.Next()) {
804 const TopoDS_Edge& edg = TopoDS::Edge(exp.Current());
805 if( nbE>1 && edg.IsSame(LastEdge) )
807 for (exp2.Init(edg,TopAbs_VERTEX); exp2.More(); exp2.Next()) {
808 if (exp2.Current().IsSame(Vlast)) {
814 LastEdge.Orientation(edg.Orientation());
818 aLocalFace = FaceRef.Oriented(wfirst.Orientation());
819 C2d = BRep_Tool::CurveOnSurface(LastEdge, TopoDS::Face(aLocalFace), f, l);
820 Standard_Real dpar = (l - f)*0.01;
822 if (LastEdge.Orientation() == TopAbs_FORWARD) {
823 C2d->D1(l,plast,dlast);
824 if (dlast.Magnitude() < gp::Resolution())
826 gp_Pnt2d PrevPnt = C2d->Value(l - dpar);
827 dlast.SetXY(plast.XY() - PrevPnt.XY());
831 C2d->D1(f,plast,dlast);
832 if (dlast.Magnitude() < gp::Resolution())
834 gp_Pnt2d NextPnt = C2d->Value(f + dpar);
835 dlast.SetXY(NextPnt.XY() - plast.XY());
840 Standard_Boolean cond;
844 cond = !(Vfirst.IsSame(Vlast) && SameUV(pfirst,plast,BAS));
847 cond = !(Vfirst.IsSame(Vlast));
853 // On enchaine par la fin
854 TopTools_ListIteratorOfListOfShape lexp(WiresFirst);
855 for (; lexp.More(); lexp.Next()) {
856 const TopoDS_Edge& edg = TopoDS::Edge(lexp.Value());
858 orient = edg.Orientation();
859 TopExp::Vertices(edg,vdeb,vfin);
860 if (orient == TopAbs_FORWARD && Vlast.IsSame(vdeb)) {
861 PossE.Add(edg.Oriented(orient));
863 else if (orient == TopAbs_REVERSED && Vlast.IsSame(vfin)) {
864 PossE.Add(edg.Oriented(orient));
867 nbPoss = PossE.Extent();
873 TopoDS_Edge aNextEdge;
875 aNextEdge = TopoDS::Edge (PossE.FindKey (1));
876 TopoDS_Shape aLocalFace = FaceRef.Oriented(wfirst.Orientation());
877 C2d = BRep_Tool::CurveOnSurface(aNextEdge,
878 TopoDS::Face(aLocalFace), f, l);
879 Standard_Real dpar = (l - f)*0.01;
881 if (aNextEdge.Orientation() == TopAbs_FORWARD) {
882 C2d->D1(l,plast,dlast);
883 if (dlast.Magnitude() < gp::Resolution())
885 gp_Pnt2d PrevPnt = C2d->Value(l - dpar);
886 dlast.SetXY(plast.XY() - PrevPnt.XY());
890 C2d->D1(f,plast,dlast);
891 if (dlast.Magnitude() < gp::Resolution())
893 gp_Pnt2d NextPnt = C2d->Value(f + dpar);
894 dlast.SetXY(NextPnt.XY() - plast.XY());
899 else if (nbPoss > 1) {
900 // Faire choix en U,V...
901 TopoDS_Shape aLocalFace = FaceRef.Oriented(wfirst.Orientation());
903 ChoixUV(LastEdge, TopoDS::Face(aLocalFace), PossE,
904 aNextEdge, plast, dlast, toll);
908 if (aNextEdge.IsNull())
910 // loop is not closed. Split is not possible
911 Standard_ConstructionError::Raise("Split is not possible: split loop is not closed");
914 if (MapE.Contains(aNextEdge))
916 B.Add(newW1, aNextEdge);
918 LastEdge = aNextEdge;
920 if (LastEdge.Orientation() == TopAbs_FORWARD) {
921 Vlast = TopExp::LastVertex(LastEdge);
924 Vlast = TopExp::FirstVertex(LastEdge);
927 toll = BRep_Tool::Tolerance(Vlast);
928 tol1 = Max(tolf, toll);
931 //MODIFICATION PIERRE SMEYERS : si pas de possibilite, on sort avec erreur
933 cout<<"erreur Spliter : pas de chainage du wire"<<endl;
934 Standard_ConstructionError::Raise();
938 tol1 = Max(BAS.UResolution(tol1), BAS.VResolution(tol1));
942 TopTools_ListIteratorOfListOfShape lexp(WiresFirst);
943 for (; lexp.More(); lexp.Next()) {
944 const TopoDS_Edge& edg = TopoDS::Edge(lexp.Value());
945 if (!MapE.Contains(edg)) {
951 TopoDS_Face newF1,newF2;
952 aLocalFace = FaceRef.EmptyCopied();
953 newF1 = TopoDS::Face(aLocalFace);
954 newF1.Orientation(TopAbs_FORWARD);
955 aLocalFace = FaceRef.EmptyCopied();
956 newF2 = TopoDS::Face(aLocalFace);
957 newF2.Orientation(TopAbs_FORWARD);
959 // modifs JAG 97.05.28
961 TopAbs_Orientation orfila=TopAbs_FORWARD;
963 for (exp.Init(FaceRef.Oriented(TopAbs_FORWARD),TopAbs_WIRE);
964 exp.More(); exp.Next()) {
965 const TopoDS_Wire& wir = TopoDS::Wire(exp.Current());
966 if (wir.IsSame(wfirst)) {
967 orfila = exp.Current().Orientation();
972 //newW1.Oriented(orfila);
973 //newW2.Oriented(orfila);
976 //BRepTools::Write(newF1, "k:/queries/WrongBOP/NewF1.brep");
978 //BRepTools::Write(newF2, "k:/queries/WrongBOP/NewF2.brep");
980 for (exp.ReInit(); exp.More(); exp.Next()) {
981 const TopoDS_Wire& wir = TopoDS::Wire(exp.Current());
982 if (!wir.IsSame(wfirst)) {
983 if (IsInside(newF1, wir)) {
986 else if (IsInside(newF2, wir)) {
990 // Ce wire est ni dans newF2 ni dans newF1
991 // Peut etre faut il construire une troisieme face
992 cout << "WARNING: LocOpe_SPlitShape : Ce wire est ni dans newF2 ni dans newF1" << endl;
999 // Mise a jour des descendants des wires
1000 for (exp.Init(F,TopAbs_WIRE); exp.More(); exp.Next()) {
1001 TopTools_ListOfShape& ls = myMap(exp.Current());
1003 for (; itl.More(); itl.Next()) {
1004 if (itl.Value().IsSame(wfirst)) {
1008 if (itl.More()) { // on a trouve le wire
1016 // on ne cree qu`une seule face
1017 TopoDS_Wire outerW = BRepTools::OuterWire(FaceRef);
1018 TopoDS_Wire newWire;
1019 TopoDS_Face newFace;
1020 B.MakeWire(newWire);
1021 newWire.Orientation(TopAbs_FORWARD);
1022 TopAbs_Orientation orient,orRelat;
1024 if (wfirst.Orientation() == wlast.Orientation()) {
1025 orRelat = TopAbs_FORWARD;
1028 orRelat = TopAbs_REVERSED;
1031 if (wlast.IsSame(outerW)) {
1037 for (exp.Init(wfirst.Oriented(TopAbs_FORWARD),TopAbs_EDGE);
1038 exp.More(); exp.Next()) {
1039 B.Add(newWire,TopoDS::Edge(exp.Current()));
1043 for (exp.Init(wlast.Oriented(TopAbs_FORWARD),TopAbs_EDGE);
1044 exp.More(); exp.Next()) {
1045 const TopoDS_Edge& edg = TopoDS::Edge(exp.Current());
1046 orient = TopAbs::Compose(edg.Orientation(),orRelat);
1047 B.Add(newWire,edg.Oriented(orient));
1051 // Edges du wire ajoute, et dans les 2 sens
1052 for (exp.Init(W.Oriented(TopAbs_FORWARD),TopAbs_EDGE);
1053 exp.More(); exp.Next()) {
1054 const TopoDS_Edge& edg = TopoDS::Edge(exp.Current());
1055 orient = edg.Orientation();
1056 B.Add(newWire,edg.Oriented(orient));
1057 B.Add(newWire,edg.Oriented(TopAbs::Reverse(orient)));
1058 myDblE.Add(edg.Oriented(orient));
1061 // on refait une face
1063 TopoDS_Shape aLocalFace = FaceRef.EmptyCopied();
1064 newFace = TopoDS::Face(aLocalFace);
1065 // newFace = TopoDS::Face(FaceRef.EmptyCopied());
1066 FaceRef.Orientation(TopAbs_FORWARD);
1067 for (exp.Init(FaceRef.Oriented(TopAbs_FORWARD),TopAbs_WIRE);
1068 exp.More(); exp.Next()) {
1069 const TopoDS_Wire& wir = TopoDS::Wire(exp.Current());
1070 if (wir.IsSame(wfirst)) {
1071 B.Add(newFace,newWire.Oriented(wir.Orientation()));
1073 else if (!wir.IsSame(wlast)) {
1079 // Mise a jour des descendants des wires
1080 for (exp.Init(F,TopAbs_WIRE); exp.More(); exp.Next()) {
1081 TopTools_ListOfShape& ls = myMap(exp.Current());
1083 Standard_Boolean touch = Standard_False;
1084 while (itl.More()) {
1085 if (itl.Value().IsSame(wfirst) || itl.Value().IsSame(wlast)) {
1087 touch = Standard_True;
1102 //=======================================================================
1105 //=======================================================================
1107 const TopTools_ListOfShape& LocOpe_SplitShape::LeftOf(const TopoDS_Wire& W,
1108 const TopoDS_Face& F)
1110 if (myShape.IsNull()) {
1111 Standard_NoSuchObject::Raise();
1114 TopExp_Explorer exp,expw,expf;
1115 exp.Init(myShape,TopAbs_FACE);
1116 for (; exp.More(); exp.Next()) {
1117 if (exp.Current().IsSame(F)) {
1122 Standard_NoSuchObject::Raise();
1126 const TopoDS_Face& theFace = TopoDS::Face(exp.Current());
1127 TopAbs_Orientation orFace = theFace.Orientation();
1128 TopTools_ListIteratorOfListOfShape itl,itl2;
1130 for (expw.Init(W,TopAbs_EDGE); expw.More(); expw.Next()) {
1131 const TopoDS_Edge& edg = TopoDS::Edge(expw.Current());
1132 for (itl.Initialize(myMap(theFace)); itl.More(); itl.Next()) {
1133 TopoDS_Face fac = TopoDS::Face(itl.Value());
1134 fac.Orientation(orFace);
1135 for (expf.Init(fac,TopAbs_EDGE); expf.More(); expf.Next()) {
1136 const TopoDS_Edge& edgbis = TopoDS::Edge(expf.Current());
1137 if (edgbis.IsSame(edg) &&
1138 edgbis.Orientation() == edg.Orientation()) {
1139 for (itl2.Initialize(myLeft); itl2.More(); itl2.Next()) {
1140 if (itl2.Value().IsSame(fac)) {
1144 if (!itl2.More()) { // la face n`est pas deja presente
1150 if (expf.More()) { // face found
1159 //=======================================================================
1160 //function : DescendantShapes
1162 //=======================================================================
1164 const TopTools_ListOfShape& LocOpe_SplitShape::DescendantShapes
1165 (const TopoDS_Shape& S)
1169 myDone = Standard_True;
1172 if (!myDblE.IsEmpty()) {
1173 cout << "Le shape comporte des faces invalides" << endl;
1181 //=======================================================================
1184 //=======================================================================
1186 void LocOpe_SplitShape::Put(const TopoDS_Shape& S)
1188 if (!myMap.IsBound(S)) {
1189 TopTools_ListOfShape thelist;
1190 myMap.Bind(S, thelist);
1191 if (S.ShapeType() != TopAbs_VERTEX) {
1192 for(TopoDS_Iterator theIterator(S);theIterator.More();
1193 theIterator.Next()) {
1194 Put(theIterator.Value());
1204 //=======================================================================
1205 //function : Rebuild
1207 //=======================================================================
1209 Standard_Boolean LocOpe_SplitShape::Rebuild(const TopoDS_Shape& S)
1213 TopTools_ListIteratorOfListOfShape itr(myMap(S));
1215 if (itr.Value().IsSame(S)) {
1216 return Standard_False;
1218 return Standard_True;
1220 Standard_Boolean rebuild = Standard_False;
1222 for(it.Initialize(S); it.More(); it.Next()) {
1223 rebuild = Rebuild(it.Value()) || rebuild;
1228 TopoDS_Shape result = S.EmptyCopied();
1229 TopAbs_Orientation orient;
1230 for(it.Initialize(S); it.More(); it.Next()) {
1231 orient = it.Value().Orientation();
1232 for (itr.Initialize(myMap(it.Value())); itr.More(); itr.Next()) {
1233 B.Add(result,itr.Value().Oriented(orient));
1236 result.Closed (BRep_Tool::IsClosed(result));
1237 myMap(S).Append(result);
1247 //=======================================================================
1248 //function : IsInside
1250 //=======================================================================
1252 static Standard_Boolean IsInside(const TopoDS_Face& F,
1253 const TopoDS_Wire& W1,
1254 const TopoDS_Wire& W2)
1256 // Attention, c`est tres boeuf !!!!
1258 TopoDS_Shape aLocalShape = F.EmptyCopied();
1259 TopoDS_Face newFace = TopoDS::Face(aLocalShape);
1260 // TopoDS_Face newFace = TopoDS::Face(F.EmptyCopied());
1262 //TopAbs_Orientation orWire = W2.Orientation();
1264 newFace.Orientation(TopAbs_FORWARD);
1267 // BRepGProp::SurfaceProperties(newFace,GP);
1268 // if (GP.Mass() < 0) {
1269 BRepTopAdaptor_FClass2d classif(newFace,Precision::PConfusion());
1270 Standard_Boolean Reversed = Standard_False;
1271 if (classif.PerformInfinitePoint() == TopAbs_IN) {
1272 //le wire donne defini un trou
1273 // newFace = TopoDS::Face(F.EmptyCopied());
1274 // newFace.Orientation(TopAbs_FORWARD);
1275 // orWire = TopAbs::Reverse(orWire);
1276 // B.Add(newFace,W2.Oriented(orWire));
1277 Reversed = Standard_True;
1280 // Standard_Real U,V;
1281 TopExp_Explorer exp(W1,TopAbs_EDGE);
1282 const TopoDS_Edge& edg = TopoDS::Edge(exp.Current());
1283 TopExp_Explorer exp2(edg,TopAbs_VERTEX);
1284 const TopoDS_Vertex& vtx = TopoDS::Vertex(exp2.Current());
1285 Standard_Real prm = BRep_Tool::Parameter(vtx,edg);
1287 Handle(Geom2d_Curve) C2d = BRep_Tool::CurveOnSurface(edg,F,f,l);
1290 cout << "Edge is not on surface" <<endl;
1292 return Standard_False;
1294 gp_Pnt2d pt2d(C2d->Value(prm));
1295 // BRepClass_FaceClassifier classif(newFace,pt2d,Precision::PConfusion());
1296 // return (classif.State() == TopAbs_IN);
1298 return (classif.Perform(pt2d) == TopAbs_IN);
1301 return (classif.Perform(pt2d) == TopAbs_OUT);
1306 //=======================================================================
1307 //function : IsInside
1309 //=======================================================================
1311 static Standard_Boolean IsInside(const TopoDS_Face& F,
1312 const TopoDS_Wire& W)
1314 // Attention, c`est tres boeuf !!!!
1315 TopExp_Explorer exp(W,TopAbs_EDGE);
1316 for( ; exp.More(); exp.Next()) {
1317 const TopoDS_Edge& edg = TopoDS::Edge(exp.Current());
1318 // TopExp_Explorer exp2(edg,TopAbs_VERTEX);
1319 // const TopoDS_Vertex& vtx = TopoDS::Vertex(exp2.Current());
1320 // Standard_Real prm = BRep_Tool::Parameter(vtx,edg);
1321 Standard_Real f,l,prm;
1322 Handle(Geom2d_Curve) C2d = BRep_Tool::CurveOnSurface(edg,F,f,l);
1323 if (!Precision::IsNegativeInfinite(f) &&
1324 !Precision::IsPositiveInfinite(l)) {
1328 if (Precision::IsNegativeInfinite(f) &&
1329 Precision::IsPositiveInfinite(l)){
1332 else if (Precision::IsNegativeInfinite(f)) {
1340 gp_Pnt2d pt2d(C2d->Value(prm));
1341 // BRepClass_FaceClassifier classif(F,pt2d,Precision::PConfusion());
1342 // return (classif.State() != TopAbs_OUT);
1343 BRepTopAdaptor_FClass2d classif(F,Precision::PConfusion());
1344 TopAbs_State stat = classif.Perform(pt2d);
1345 // return (classif.Perform(pt2d) != TopAbs_OUT);
1346 if(stat == TopAbs_OUT) return Standard_False;
1348 if(stat == TopAbs_ON) {
1349 Standard_Integer nbPnt =10;
1350 Standard_Integer nbOut =0,nbIn =0,nbOn=0;
1351 Standard_Integer j =1;
1352 for( ; j<= nbPnt ; j++)
1354 //check neighbouring point
1355 //prm = .66 * prm + .34 * l;
1356 prm = f + (l-f)/nbPnt*(j-1);
1357 pt2d = C2d->Value(prm);
1358 stat = classif.Perform(pt2d);
1359 if(stat == TopAbs_OUT )
1361 else if(stat == TopAbs_IN)
1366 if(nbOut > nbIn + nbOn)
1367 return Standard_False;
1370 return Standard_True;
1373 //=======================================================================
1374 //function : GetDirection
1376 //=======================================================================
1377 static void GetDirection(const TopoDS_Edge& theEdge,
1378 const TopoDS_Face& theFace,
1379 Standard_Real& theTol,
1383 Standard_Real aFirst, aLast;
1384 Handle(Geom2d_Curve) aC2d = BRep_Tool::CurveOnSurface (theEdge, theFace, aFirst, aLast);
1386 TopAbs_Orientation anOr = theEdge.Orientation();
1388 if (anOr == TopAbs_FORWARD)
1390 aVtx = TopExp::FirstVertex (theEdge);
1391 aC2d->D0 (aFirst, thePnt);
1395 aVtx = TopExp::LastVertex (theEdge);
1396 aC2d->D0 (aLast, thePnt);
1399 BRepAdaptor_Surface aSurf (theFace, Standard_False);
1400 theTol = BRep_Tool::Tolerance (aVtx);
1401 Standard_Real aTol = Max (aSurf.UResolution (theTol), aSurf.VResolution (theTol));
1402 aTol = Min (aTol, (aLast - aFirst)*0.1);
1406 if (anOr == TopAbs_FORWARD)
1409 aC2d->D0 (aFirst, aP2d);
1414 aC2d->D0 (aLast, aP2d);
1416 theDir = gp_Vec2d (thePnt, aP2d);
1419 //=======================================================================
1420 //function : ChoixUV
1422 //=======================================================================
1424 static void ChoixUV(const TopoDS_Edge& Last,
1425 const TopoDS_Face& F,
1426 const TopTools_IndexedMapOfShape& Poss,
1427 TopoDS_Edge& theResEdge,
1430 const Standard_Real toll)
1436 gp_Pnt aPCur, aPlst;
1438 BRepAdaptor_Surface surf(F,Standard_False); // no restriction
1439 surf.D0 (plst.X(), plst.Y(), aPlst);
1443 gp_Dir2d ref2d(dlst);
1445 Handle(Geom2d_Curve) C2d;
1448 Standard_Integer index = 0, imin=0;
1449 Standard_Real angmax = -M_PI, dist, ang;
1452 for (index = 1; index <= Poss.Extent(); index++) {
1453 TopoDS_Edge anEdge = TopoDS::Edge (Poss.FindKey (index));
1454 GetDirection (anEdge, F, tol, p2d, v2d);
1456 surf.D0 (p2d.X(), p2d.Y(), aPCur);
1458 tol = Max(toll, tol); tol *= tol;
1460 dist = aPCur.SquareDistance(aPlst);
1462 if (!Last.IsSame(anEdge)) {
1463 ang = ref2d.Angle(gp_Dir2d(v2d));
1469 if ((dist < tol) && (ang > angmax)) {
1477 theResEdge = TopoDS::Edge (Poss.FindKey (imin));
1478 C2d = BRep_Tool::CurveOnSurface (theResEdge, F, f, l);
1479 dpar = (l - f)*0.01;
1480 if (theResEdge.Orientation() == TopAbs_FORWARD)
1482 C2d->D1 (l, plst, dlst);
1483 if (dlst.Magnitude() < gp::Resolution())
1485 gp_Pnt2d PrevPnt = C2d->Value(l - dpar);
1486 dlst.SetXY(plst.XY() - PrevPnt.XY());
1491 C2d->D1 (f, plst, dlst);
1492 if (dlst.Magnitude() < gp::Resolution())
1494 gp_Pnt2d NextPnt = C2d->Value(f + dpar);
1495 dlst.SetXY(NextPnt.XY() - plst.XY());
1503 //=======================================================================
1504 //function : ChooseDirection
1506 //=======================================================================
1508 static TopoDS_Shape ChooseDirection(const TopoDS_Shape& RefDir,
1509 const TopoDS_Vertex& RefVertex,
1510 const TopoDS_Face& theFace,
1511 const TopTools_ListOfShape& Ldirs)
1513 TopExp_Explorer Explo(RefDir, TopAbs_EDGE);
1514 TopoDS_Edge RefEdge;
1515 TopoDS_Vertex V1, V2;
1516 TopAbs_Orientation anOr = TopAbs_FORWARD;
1517 for (; Explo.More(); Explo.Next())
1519 RefEdge = TopoDS::Edge(Explo.Current());
1520 TopExp::Vertices(RefEdge, V1, V2);
1521 if (V1.IsSame(RefVertex))
1523 anOr = TopAbs_REVERSED;
1526 else if (V2.IsSame(RefVertex))
1528 anOr = TopAbs_FORWARD;
1533 Standard_Real RefFirst, RefLast;
1534 Handle(Geom2d_Curve) RefCurve = BRep_Tool::CurveOnSurface(RefEdge, theFace, RefFirst, RefLast);
1538 //Standard_Real RefPar = (RefEdge.Orientation() == TopAbs_FORWARD)? RefLast : RefFirst;
1539 Standard_Real RefPar = (anOr == TopAbs_FORWARD)? RefLast : RefFirst;
1540 RefCurve->D1(RefPar, RefPnt, RefVec);
1541 if (anOr == TopAbs_FORWARD)
1544 Handle(Geom2d_Curve) aCurve;
1545 Standard_Real aFirst, aLast, aPar;
1547 Standard_Real MinAngle = RealLast(), anAngle;
1548 TopoDS_Shape TargetDir;
1549 TopTools_ListIteratorOfListOfShape itl(Ldirs);
1550 for (; itl.More(); itl.Next())
1552 const TopoDS_Shape& aShape = itl.Value();
1554 for (Explo.Init(aShape, TopAbs_EDGE); Explo.More(); Explo.Next())
1556 anEdge = TopoDS::Edge(Explo.Current());
1557 TopExp::Vertices(anEdge, V1, V2);
1558 if (V1.IsSame(RefVertex))
1560 anOr = TopAbs_FORWARD;
1563 else if (V2.IsSame(RefVertex))
1565 anOr = TopAbs_REVERSED;
1569 aCurve = BRep_Tool::CurveOnSurface(anEdge, theFace, aFirst, aLast);
1570 aPar = (anOr == TopAbs_FORWARD)? aFirst : aLast;
1571 aCurve->D1(aPar, RefPnt, aVec);
1572 if (anOr == TopAbs_REVERSED)
1574 anAngle = aVec.Angle(RefVec);
1578 if (anAngle < MinAngle)