1 // Created by: Peter KURNEV
2 // Copyright (c) 2010-2014 OPEN CASCADE SAS
3 // Copyright (c) 2007-2010 CEA/DEN, EDF R&D, OPEN CASCADE
4 // Copyright (c) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, CEDRAT,
5 //                         EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
6 //
7 // This file is part of Open CASCADE Technology software library.
8 //
9 // This library is free software; you can redistribute it and/or modify it under
10 // the terms of the GNU Lesser General Public License version 2.1 as published
11 // by the Free Software Foundation, with special exception defined in the file
12 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
13 // distribution for complete text of the license and disclaimer of any warranty.
14 //
15 // Alternatively, this file may be used under the terms of Open CASCADE
16 // commercial license or contractual agreement.
17 
18 
19 #include <BOPTools_AlgoTools.hxx>
20 #include <BOPAlgo_Alerts.hxx>
21 #include <BOPTools_AlgoTools2D.hxx>
22 #include <BOPTools_AlgoTools3D.hxx>
23 #include <BOPTools_CoupleOfShape.hxx>
24 #include <BOPTools_ListOfCoupleOfShape.hxx>
25 #include <BRep_Builder.hxx>
26 #include <BRep_Tool.hxx>
27 #include <BRepAdaptor_Curve2d.hxx>
28 #include <BRepAdaptor_Surface.hxx>
29 #include <BRepClass3d_SolidClassifier.hxx>
30 #include <BRepLib.hxx>
31 #include <Geom2d_Curve.hxx>
32 #include <Geom2dInt_Geom2dCurveTool.hxx>
33 #include <Geom_Curve.hxx>
34 #include <Geom_Plane.hxx>
35 #include <Geom_Surface.hxx>
36 #include <Geom_TrimmedCurve.hxx>
37 #include <GeomAPI_ProjectPointOnSurf.hxx>
38 #include <gp_Cone.hxx>
39 #include <gp_Cylinder.hxx>
40 #include <gp_Lin.hxx>
41 #include <gp_Pnt.hxx>
42 #include <gp_Pnt2d.hxx>
43 #include <gp_Sphere.hxx>
44 #include <gp_Torus.hxx>
45 #include <gp_XYZ.hxx>
46 #include <IntTools_Context.hxx>
47 #include <IntTools_Curve.hxx>
48 #include <IntTools_Range.hxx>
49 #include <IntTools_ShrunkRange.hxx>
50 #include <IntTools_Tools.hxx>
51 #include <Precision.hxx>
52 #include <TopAbs_Orientation.hxx>
53 #include <TopExp.hxx>
54 #include <TopExp_Explorer.hxx>
55 #include <TopoDS.hxx>
56 #include <TopoDS_Compound.hxx>
57 #include <TopoDS_CompSolid.hxx>
58 #include <TopoDS_Edge.hxx>
59 #include <TopoDS_Face.hxx>
60 #include <TopoDS_Shape.hxx>
61 #include <TopoDS_Shell.hxx>
62 #include <TopoDS_Solid.hxx>
63 #include <TopoDS_Vertex.hxx>
64 #include <TopoDS_Wire.hxx>
65 #include <TopTools_IndexedMapOfShape.hxx>
66 #include <TopTools_MapOfShape.hxx>
67 #include <TopTools_MapOfOrientedShape.hxx>
68 #include <Message_Report.hxx>
69 #include <NCollection_Array1.hxx>
70 #include <algorithm>
71 
72 //
73 static
74   Standard_Real AngleWithRef(const gp_Dir& theD1,
75                              const gp_Dir& theD2,
76                              const gp_Dir& theDRef);
77 
78 static
79   Standard_Boolean FindFacePairs (const TopoDS_Edge& theE,
80                                   const TopTools_ListOfShape& thLF,
81                                   BOPTools_ListOfCoupleOfShape& theLCFF,
82                                   const Handle(IntTools_Context)& theContext);
83 static
84   TopAbs_Orientation Orientation(const TopoDS_Edge& anE,
85                                  const TopoDS_Face& aF);
86 
87 static
88   Standard_Boolean GetFaceDir(const TopoDS_Edge& aE,
89                               const TopoDS_Face& aF,
90                               const gp_Pnt& aP,
91                               const Standard_Real aT,
92                               const gp_Dir& aDTgt,
93                               const Standard_Boolean theSmallFaces,
94                               gp_Dir& aDN,
95                               gp_Dir& aDB,
96                               const Handle(IntTools_Context)& theContext,
97                               GeomAPI_ProjectPointOnSurf& aProjPL,
98                               const Standard_Real aDt);
99 static
100   Standard_Boolean FindPointInFace(const TopoDS_Face& aF,
101                                    const gp_Pnt& aP,
102                                    gp_Dir& aDB,
103                                    gp_Pnt& aPOut,
104                                    const Handle(IntTools_Context)& theContext,
105                                    GeomAPI_ProjectPointOnSurf& aProjPL,
106                                    const Standard_Real aDt,
107                                    const Standard_Real aTolE);
108 static
109   Standard_Real MinStep3D(const TopoDS_Edge& theE1,
110                           const TopoDS_Face& theF1,
111                           const BOPTools_ListOfCoupleOfShape& theLCS,
112                           const gp_Pnt& aP,
113                           const Handle(IntTools_Context)& theContext,
114                           Standard_Boolean& theSmallFaces);
115 
116 
117 
118 //=======================================================================
119 // function: MakeConnexityBlocks
120 // purpose:
121 //=======================================================================
MakeConnexityBlocks(const TopoDS_Shape & theS,const TopAbs_ShapeEnum theConnectionType,const TopAbs_ShapeEnum theElementType,TopTools_ListOfListOfShape & theLCB,TopTools_IndexedDataMapOfShapeListOfShape & theConnectionMap)122 void BOPTools_AlgoTools::MakeConnexityBlocks
123   (const TopoDS_Shape& theS,
124    const TopAbs_ShapeEnum theConnectionType,
125    const TopAbs_ShapeEnum theElementType,
126    TopTools_ListOfListOfShape& theLCB,
127    TopTools_IndexedDataMapOfShapeListOfShape& theConnectionMap)
128 {
129   // Map shapes to find connected elements
130   TopExp::MapShapesAndAncestors(theS, theConnectionType, theElementType, theConnectionMap);
131   // Fence map
132   TopTools_MapOfShape aMFence;
133 
134   TopExp_Explorer aExp(theS, theElementType);
135   for (; aExp.More(); aExp.Next())
136   {
137     const TopoDS_Shape& aS = aExp.Current();
138     if (!aMFence.Add(aS)) {
139       continue;
140     }
141     // The block
142     TopTools_ListOfShape aLBlock;
143     // Start the block
144     aLBlock.Append(aS);
145     // Look for connected parts
146     TopTools_ListIteratorOfListOfShape aItB(aLBlock);
147     for (; aItB.More(); aItB.Next())
148     {
149       const TopoDS_Shape& aS1 = aItB.Value();
150       TopExp_Explorer aExpSS(aS1, theConnectionType);
151       for (; aExpSS.More(); aExpSS.Next())
152       {
153         const TopoDS_Shape& aSubS = aExpSS.Current();
154         const TopTools_ListOfShape& aLS = theConnectionMap.FindFromKey(aSubS);
155         TopTools_ListIteratorOfListOfShape aItLS(aLS);
156         for (; aItLS.More(); aItLS.Next())
157         {
158           const TopoDS_Shape& aS2 = aItLS.Value();
159           if (aMFence.Add(aS2))
160             aLBlock.Append(aS2);
161         }
162       }
163     }
164     // Add the block into result
165     theLCB.Append(aLBlock);
166   }
167 }
168 
169 //=======================================================================
170 // function: MakeConnexityBlocks
171 // purpose:
172 //=======================================================================
MakeConnexityBlocks(const TopoDS_Shape & theS,const TopAbs_ShapeEnum theConnectionType,const TopAbs_ShapeEnum theElementType,TopTools_ListOfShape & theLCB)173 void BOPTools_AlgoTools::MakeConnexityBlocks
174   (const TopoDS_Shape& theS,
175    const TopAbs_ShapeEnum theConnectionType,
176    const TopAbs_ShapeEnum theElementType,
177    TopTools_ListOfShape& theLCB)
178 {
179   TopTools_ListOfListOfShape aLBlocks;
180   TopTools_IndexedDataMapOfShapeListOfShape aCMap;
181   BOPTools_AlgoTools::MakeConnexityBlocks(theS, theConnectionType, theElementType, aLBlocks, aCMap);
182 
183   // Make compound from each block
184   TopTools_ListIteratorOfListOfListOfShape aItB(aLBlocks);
185   for (; aItB.More(); aItB.Next())
186   {
187     const TopTools_ListOfShape& aLB = aItB.Value();
188 
189     TopoDS_Compound aBlock;
190     BRep_Builder().MakeCompound(aBlock);
191     for (TopTools_ListIteratorOfListOfShape it(aLB); it.More(); it.Next())
192       BRep_Builder().Add(aBlock, it.Value());
193 
194     theLCB.Append(aBlock);
195   }
196 }
197 
198 //=======================================================================
199 // function: MakeConnexityBlocks
200 // purpose:
201 //=======================================================================
MakeConnexityBlocks(const TopTools_ListOfShape & theLS,const TopAbs_ShapeEnum theConnectionType,const TopAbs_ShapeEnum theElementType,BOPTools_ListOfConnexityBlock & theLCB)202 void BOPTools_AlgoTools::MakeConnexityBlocks
203   (const TopTools_ListOfShape& theLS,
204    const TopAbs_ShapeEnum theConnectionType,
205    const TopAbs_ShapeEnum theElementType,
206    BOPTools_ListOfConnexityBlock& theLCB)
207 {
208   BRep_Builder aBB;
209   // Make connexity blocks from start elements
210   TopoDS_Compound aCStart;
211   aBB.MakeCompound(aCStart);
212 
213   TopTools_MapOfShape aMFence, aMNRegular;
214 
215   TopTools_ListIteratorOfListOfShape aItL(theLS);
216   for (; aItL.More(); aItL.Next())
217   {
218     const TopoDS_Shape& aS = aItL.Value();
219     if (aMFence.Add(aS))
220       aBB.Add(aCStart, aS);
221     else
222       aMNRegular.Add(aS);
223   }
224 
225   TopTools_ListOfListOfShape aLCB;
226   TopTools_IndexedDataMapOfShapeListOfShape aCMap;
227   BOPTools_AlgoTools::MakeConnexityBlocks(aCStart, theConnectionType, theElementType, aLCB, aCMap);
228 
229   // Save the blocks and check their regularity
230   TopTools_ListIteratorOfListOfListOfShape aItB(aLCB);
231   for (; aItB.More(); aItB.Next())
232   {
233     const TopTools_ListOfShape& aBlock = aItB.Value();
234 
235     BOPTools_ConnexityBlock aCB;
236     TopTools_ListOfShape& aLCS = aCB.ChangeShapes();
237 
238     Standard_Boolean bRegular = Standard_True;
239     for (TopTools_ListIteratorOfListOfShape it(aBlock); it.More(); it.Next())
240     {
241       TopoDS_Shape aS = it.Value();
242       if (aMNRegular.Contains(aS))
243       {
244         bRegular = Standard_False;
245         aS.Orientation(TopAbs_FORWARD);
246         aLCS.Append(aS);
247         aS.Orientation(TopAbs_REVERSED);
248         aLCS.Append(aS);
249       }
250       else
251       {
252         aLCS.Append(aS);
253         if (bRegular)
254         {
255           // Check if there are no multi-connected shapes
256           for (TopExp_Explorer ex(aS, theConnectionType); ex.More() && bRegular; ex.Next())
257             bRegular = (aCMap.FindFromKey(ex.Current()).Extent() == 2);
258         }
259       }
260     }
261 
262     aCB.SetRegular(bRegular);
263     theLCB.Append(aCB);
264   }
265 }
266 
267 //=======================================================================
268 // function: OrientEdgesOnWire
269 // purpose: Reorient edges on wire for correct ordering
270 //=======================================================================
OrientEdgesOnWire(TopoDS_Shape & theWire)271 void BOPTools_AlgoTools::OrientEdgesOnWire(TopoDS_Shape& theWire)
272 {
273   // make vertex-edges connexity map
274   TopTools_IndexedDataMapOfShapeListOfShape aVEMap;
275   TopExp::MapShapesAndAncestors(theWire, TopAbs_VERTEX, TopAbs_EDGE, aVEMap);
276   //
277   if (aVEMap.IsEmpty()) {
278     return;
279   }
280   //
281   BRep_Builder aBB;
282   // new wire
283   TopoDS_Wire aWire;
284   aBB.MakeWire(aWire);
285   // fence map
286   TopTools_MapOfOrientedShape aMFence;
287   //
288   TopoDS_Iterator aIt(theWire);
289   for (; aIt.More(); aIt.Next()) {
290     const TopoDS_Edge& aEC = TopoDS::Edge(aIt.Value());
291     if (!aMFence.Add(aEC)) {
292       continue;
293     }
294     //
295     // add edge to a wire as it is
296     aBB.Add(aWire, aEC);
297     //
298     TopoDS_Vertex aV1, aV2;
299     TopExp::Vertices(aEC, aV1, aV2, Standard_True);
300     //
301     if (aV1.IsSame(aV2)) {
302       // closed edge, go to the next edge
303       continue;
304     }
305     //
306     // orient the adjacent edges
307     for (Standard_Integer i = 0; i < 2; ++i) {
308       TopoDS_Shape aVC = !i ? aV1 : aV2;
309       //
310       for (;;) {
311         const TopTools_ListOfShape& aLE = aVEMap.FindFromKey(aVC);
312         if (aLE.Extent() != 2) {
313           // free vertex or multi-connexity, go to the next edge
314           break;
315         }
316         //
317         Standard_Boolean bStop = Standard_True;
318         //
319         TopTools_ListIteratorOfListOfShape aItLE(aLE);
320         for (; aItLE.More(); aItLE.Next()) {
321           const TopoDS_Edge& aEN = TopoDS::Edge(aItLE.Value());
322           if (aMFence.Contains(aEN)) {
323             continue;
324           }
325           //
326           TopoDS_Vertex aVN1, aVN2;
327           TopExp::Vertices(aEN, aVN1, aVN2, Standard_True);
328           if (aVN1.IsSame(aVN2)) {
329             // closed edge, go to the next edge
330             break;
331           }
332           //
333           // change orientation if necessary and go to the next edges
334           if ((!i && aVC.IsSame(aVN2)) || (i && aVC.IsSame(aVN1))) {
335             aBB.Add(aWire, aEN);
336           }
337           else {
338             aBB.Add(aWire, aEN.Reversed());
339           }
340           aMFence.Add(aEN);
341           aVC = aVC.IsSame(aVN1) ? aVN2 : aVN1;
342           bStop = Standard_False;
343           break;
344         }
345         //
346         if (bStop) {
347           break;
348         }
349       }
350     }
351   }
352   //
353   theWire = aWire;
354 }
355 //=======================================================================
356 // function: OrientFacesOnShell
357 // purpose:
358 //=======================================================================
OrientFacesOnShell(TopoDS_Shape & aShell)359 void BOPTools_AlgoTools::OrientFacesOnShell (TopoDS_Shape& aShell)
360 {
361   Standard_Boolean bIsProcessed1, bIsProcessed2;
362   Standard_Integer i, aNbE, aNbF, j;
363   TopAbs_Orientation anOrE1, anOrE2;
364   TopoDS_Face aF1x, aF2x;
365   TopoDS_Shape aShellNew;
366   TopTools_IndexedDataMapOfShapeListOfShape aEFMap;
367   TopTools_IndexedMapOfShape aProcessedFaces;
368   BRep_Builder aBB;
369   //
370   BOPTools_AlgoTools::MakeContainer(TopAbs_SHELL, aShellNew);
371   //
372   TopExp::MapShapesAndAncestors(aShell,
373                                   TopAbs_EDGE, TopAbs_FACE,
374                                   aEFMap);
375   aNbE=aEFMap.Extent();
376   //
377   // One seam edge  in aEFMap contains  2 equivalent faces.
378   for (i=1; i<=aNbE; ++i) {
379     TopTools_ListOfShape& aLF=aEFMap.ChangeFromIndex(i);
380     aNbF=aLF.Extent();
381     if (aNbF>1) {
382       TopTools_ListOfShape aLFTmp;
383       TopTools_IndexedMapOfShape aFM;
384       //
385       TopTools_ListIteratorOfListOfShape anIt(aLF);
386       for (; anIt.More(); anIt.Next()) {
387         const TopoDS_Shape& aF=anIt.Value();
388         if (!aFM.Contains(aF)) {
389           aFM.Add(aF);
390           aLFTmp.Append(aF);
391         }
392       }
393       aLF.Clear();
394       aLF=aLFTmp;
395     }
396   }
397   //
398   // Do
399   for (i=1; i<=aNbE; ++i) {
400     const TopoDS_Edge& aE=(*(TopoDS_Edge*)(&aEFMap.FindKey(i)));
401     if (BRep_Tool::Degenerated(aE)) {
402       continue;
403     }
404     //
405     const TopTools_ListOfShape& aLF=aEFMap.FindFromIndex(i);
406     aNbF=aLF.Extent();
407     if (aNbF!=2) {
408       continue;
409     }
410     //
411     TopoDS_Face& aF1=(*(TopoDS_Face*)(&aLF.First()));
412     TopoDS_Face& aF2=(*(TopoDS_Face*)(&aLF.Last()));
413     //
414     bIsProcessed1=aProcessedFaces.Contains(aF1);
415     bIsProcessed2=aProcessedFaces.Contains(aF2);
416     if (bIsProcessed1 && bIsProcessed2) {
417       continue;
418     }
419 
420     if (!bIsProcessed1 && !bIsProcessed2) {
421       aProcessedFaces.Add(aF1);
422       aBB.Add(aShellNew, aF1);
423       bIsProcessed1=!bIsProcessed1;
424     }
425     //
426     aF1x=aF1;
427     if (bIsProcessed1) {
428       j=aProcessedFaces.FindIndex(aF1);
429       aF1x=(*(TopoDS_Face*)(&aProcessedFaces.FindKey(j)));
430     }
431     //
432     aF2x=aF2;
433     if (bIsProcessed2) {
434       j=aProcessedFaces.FindIndex(aF2);
435       aF2x=(*(TopoDS_Face*)(&aProcessedFaces.FindKey(j)));
436     }
437     //
438     anOrE1=Orientation(aE, aF1x);
439     anOrE2=Orientation(aE, aF2x);
440     //
441     if (bIsProcessed1 && !bIsProcessed2) {
442       if (anOrE1==anOrE2) {
443         if (!BRep_Tool::IsClosed(aE, aF1) &&
444             !BRep_Tool::IsClosed(aE, aF2)) {
445           aF2.Reverse();
446         }
447       }
448       aProcessedFaces.Add(aF2);
449       aBB.Add(aShellNew, aF2);
450     }
451     else if (!bIsProcessed1 && bIsProcessed2) {
452       if (anOrE1==anOrE2) {
453         if (!BRep_Tool::IsClosed(aE, aF1) &&
454             !BRep_Tool::IsClosed(aE, aF2)) {
455           aF1.Reverse();
456         }
457       }
458       aProcessedFaces.Add(aF1);
459       aBB.Add(aShellNew, aF1);
460     }
461   }
462   //
463   //
464   for (i=1; i<=aNbE; ++i) {
465     const TopoDS_Edge& aE=(*(TopoDS_Edge*)(&aEFMap.FindKey(i)));
466     if (BRep_Tool::Degenerated(aE)) {
467       continue;
468     }
469     //
470     const TopTools_ListOfShape& aLF=aEFMap.FindFromIndex(i);
471     aNbF=aLF.Extent();
472     if (aNbF!=2) {
473       TopTools_ListIteratorOfListOfShape anIt(aLF);
474       for(; anIt.More(); anIt.Next()) {
475         const TopoDS_Face& aF=(*(TopoDS_Face*)(&anIt.Value()));
476         if (!aProcessedFaces.Contains(aF)) {
477           aProcessedFaces.Add(aF);
478           aBB.Add(aShellNew, aF);
479         }
480       }
481     }
482   }
483   aShell=aShellNew;
484 }
485 //=======================================================================
486 //function : Orientation
487 //purpose  :
488 //=======================================================================
Orientation(const TopoDS_Edge & anE,const TopoDS_Face & aF)489 TopAbs_Orientation Orientation(const TopoDS_Edge& anE,
490                                const TopoDS_Face& aF)
491 {
492   TopAbs_Orientation anOr=TopAbs_INTERNAL;
493 
494   TopExp_Explorer anExp;
495   anExp.Init(aF, TopAbs_EDGE);
496   for (; anExp.More(); anExp.Next()) {
497     const TopoDS_Edge& anEF1=(*(TopoDS_Edge*)(&anExp.Current()));
498     if (anEF1.IsSame(anE)) {
499       anOr=anEF1.Orientation();
500       break;
501     }
502   }
503   return anOr;
504 }
505 //=======================================================================
506 // function: MakeConnexityBlock.
507 // purpose:
508 //=======================================================================
MakeConnexityBlock(TopTools_ListOfShape & theLFIn,TopTools_IndexedMapOfShape & theMEAvoid,TopTools_ListOfShape & theLCB,const Handle (NCollection_BaseAllocator)& theAllocator)509 void BOPTools_AlgoTools::MakeConnexityBlock
510   (TopTools_ListOfShape& theLFIn,
511    TopTools_IndexedMapOfShape& theMEAvoid,
512    TopTools_ListOfShape& theLCB,
513    const Handle(NCollection_BaseAllocator)& theAllocator)
514 {
515   Standard_Integer  aNbF, aNbAdd1, aNbAdd, i;
516   TopExp_Explorer aExp;
517   TopTools_ListIteratorOfListOfShape aIt;
518   //
519   TopTools_IndexedMapOfShape aMCB(100, theAllocator);
520   TopTools_IndexedMapOfShape aMAdd(100, theAllocator);
521   TopTools_IndexedMapOfShape aMAdd1(100, theAllocator);
522   TopTools_IndexedDataMapOfShapeListOfShape aMEF(100, theAllocator);
523   //
524   // 1. aMEF
525   aNbF=theLFIn.Extent();
526   aIt.Initialize(theLFIn);
527   for (; aIt.More(); aIt.Next()) {
528     const TopoDS_Shape& aF=aIt.Value();
529     TopExp::MapShapesAndAncestors(aF, TopAbs_EDGE, TopAbs_FACE, aMEF);
530   }
531   //
532   // 2. aMCB
533   const TopoDS_Shape& aF1=theLFIn.First();
534   aMAdd.Add(aF1);
535   //
536   for(;;) {
537     aMAdd1.Clear();
538     aNbAdd = aMAdd.Extent();
539     for (i=1; i<=aNbAdd; ++i) {
540       const TopoDS_Shape& aF=aMAdd(i);
541       //
542       //aMAdd1.Clear();
543       aExp.Init(aF, TopAbs_EDGE);
544       for (; aExp.More(); aExp.Next()) {
545         const TopoDS_Shape& aE=aExp.Current();
546         if (theMEAvoid.Contains(aE)){
547           continue;
548         }
549         //
550         const TopTools_ListOfShape& aLF=aMEF.FindFromKey(aE);
551         aIt.Initialize(aLF);
552         for (; aIt.More(); aIt.Next()) {
553           const TopoDS_Shape& aFx=aIt.Value();
554           if (aFx.IsSame(aF)) {
555             continue;
556           }
557           if (aMCB.Contains(aFx)) {
558             continue;
559           }
560           aMAdd1.Add(aFx);
561         }
562       }//for (; aExp.More(); aExp.Next()){
563       aMCB.Add(aF);
564     }// for (i=1; i<=aNbAdd; ++i) {
565     //
566     aNbAdd1=aMAdd1.Extent();
567     if (!aNbAdd1) {
568       break;
569     }
570     //
571     aMAdd.Clear();
572     for (i=1; i<=aNbAdd1; ++i) {
573       const TopoDS_Shape& aFAdd=aMAdd1(i);
574       aMAdd.Add(aFAdd);
575     }
576     //
577   }//while(1) {
578 
579   //
580   aNbF=aMCB.Extent();
581   for (i=1; i<=aNbF; ++i) {
582     const TopoDS_Shape& aF=aMCB(i);
583     theLCB.Append(aF);
584   }
585 }
586 //=======================================================================
587 // function:  ComputeStateByOnePoint
588 // purpose:
589 //=======================================================================
ComputeStateByOnePoint(const TopoDS_Shape & theS,const TopoDS_Solid & theRef,const Standard_Real theTol,const Handle (IntTools_Context)& theContext)590 TopAbs_State BOPTools_AlgoTools::ComputeStateByOnePoint
591   (const TopoDS_Shape& theS,
592    const TopoDS_Solid& theRef,
593    const Standard_Real theTol,
594    const Handle(IntTools_Context)& theContext)
595 {
596   TopAbs_State aState = TopAbs_UNKNOWN;
597   TopAbs_ShapeEnum aType = theS.ShapeType();
598 
599   switch (aType)
600   {
601     case TopAbs_VERTEX:
602       aState = ComputeState(TopoDS::Vertex(theS), theRef, theTol, theContext);
603       break;
604     case TopAbs_EDGE:
605       aState = ComputeState(TopoDS::Edge(theS), theRef, theTol, theContext);
606       break;
607     case TopAbs_FACE:
608     {
609       TopTools_IndexedMapOfShape aBounds;
610       TopExp::MapShapes(theRef, TopAbs_EDGE, aBounds);
611       aState = ComputeState(TopoDS::Face(theS), theRef, theTol, aBounds, theContext);
612       break;
613     }
614     default:
615     {
616       TopoDS_Iterator it(theS);
617       if (it.More())
618         ComputeStateByOnePoint(it.Value(), theRef, theTol, theContext);
619       break;
620     }
621   }
622   return aState;
623 }
624 
625 //=======================================================================
626 // function:  ComputeState
627 // purpose:
628 //=======================================================================
ComputeState(const TopoDS_Face & theF,const TopoDS_Solid & theRef,const Standard_Real theTol,const TopTools_IndexedMapOfShape & theBounds,const Handle (IntTools_Context)& theContext)629 TopAbs_State BOPTools_AlgoTools::ComputeState
630   (const TopoDS_Face& theF,
631    const TopoDS_Solid& theRef,
632    const Standard_Real theTol,
633    const TopTools_IndexedMapOfShape& theBounds,
634    const Handle(IntTools_Context)& theContext)
635 {
636   TopAbs_State aState = TopAbs_UNKNOWN;
637 
638   // Try to find the edge on the face which does not
639   // belong to the solid and classify the middle point of that
640   // edge relatively solid.
641   TopExp_Explorer aExp(theF, TopAbs_EDGE);
642   for (; aExp.More(); aExp.Next())
643   {
644     const TopoDS_Edge& aSE = (*(TopoDS_Edge*)(&aExp.Current()));
645     if (BRep_Tool::Degenerated(aSE))
646       continue;
647 
648     if (!theBounds.Contains(aSE))
649     {
650       aState = BOPTools_AlgoTools::ComputeState(aSE, theRef, theTol, theContext);
651       return aState;
652     }
653   }
654 
655   // All edges of the face are on the solid.
656   // Get point inside the face and classify it relatively solid.
657   gp_Pnt aP3D;
658   gp_Pnt2d aP2D;
659   Standard_Integer iErr = BOPTools_AlgoTools3D::PointInFace(theF, aP3D, aP2D, theContext);
660   if (iErr != 0)
661   {
662     // Hatcher fails to find the point -> get point near some edge
663     aExp.Init(theF, TopAbs_EDGE);
664     for (; aExp.More() && iErr != 0; aExp.Next())
665     {
666       const TopoDS_Edge& aSE = TopoDS::Edge(aExp.Current());
667       if (BRep_Tool::Degenerated(aSE))
668         continue;
669 
670       iErr = BOPTools_AlgoTools3D::PointNearEdge(aSE, theF, aP2D, aP3D, theContext);
671     }
672   }
673 
674   if (iErr == 0)
675     aState = BOPTools_AlgoTools::ComputeState(aP3D, theRef, theTol, theContext);
676 
677   return aState;
678 }
679 //=======================================================================
680 // function:  ComputeState
681 // purpose:
682 //=======================================================================
ComputeState(const TopoDS_Vertex & theV,const TopoDS_Solid & theRef,const Standard_Real theTol,const Handle (IntTools_Context)& theContext)683 TopAbs_State BOPTools_AlgoTools::ComputeState
684   (const TopoDS_Vertex& theV,
685    const TopoDS_Solid& theRef,
686    const Standard_Real theTol,
687    const Handle(IntTools_Context)& theContext)
688 {
689   TopAbs_State aState;
690   gp_Pnt aP3D;
691   //
692   aP3D=BRep_Tool::Pnt(theV);
693   aState=BOPTools_AlgoTools::ComputeState(aP3D, theRef, theTol,
694                                           theContext);
695   return aState;
696 }
697 //=======================================================================
698 // function:  ComputeState
699 // purpose:
700 //=======================================================================
ComputeState(const TopoDS_Edge & theE,const TopoDS_Solid & theRef,const Standard_Real theTol,const Handle (IntTools_Context)& theContext)701 TopAbs_State BOPTools_AlgoTools::ComputeState
702   (const TopoDS_Edge& theE,
703    const TopoDS_Solid& theRef,
704    const Standard_Real theTol,
705    const Handle(IntTools_Context)& theContext)
706 {
707   Standard_Real aT1, aT2, aT = 0.;
708   TopAbs_State aState;
709   Handle(Geom_Curve) aC3D;
710   gp_Pnt aP3D;
711   //
712   aC3D = BRep_Tool::Curve(theE, aT1, aT2);
713   //
714   if(aC3D.IsNull()) {
715     //it means that we are in degenerated edge
716     const TopoDS_Vertex& aV = TopExp::FirstVertex(theE);
717     if(aV.IsNull()){
718       return TopAbs_UNKNOWN;
719     }
720     aP3D=BRep_Tool::Pnt(aV);
721   }
722   else {//usual case
723     Standard_Boolean bF2Inf, bL2Inf;
724     Standard_Real dT=10.;
725     //
726     bF2Inf = Precision::IsNegativeInfinite(aT1);
727     bL2Inf = Precision::IsPositiveInfinite(aT2);
728     //
729     if (bF2Inf && !bL2Inf) {
730       aT=aT2-dT;
731     }
732     else if (!bF2Inf && bL2Inf) {
733       aT=aT1+dT;
734     }
735     else if (bF2Inf && bL2Inf) {
736       aT=0.;
737     }
738     else {
739       aT=IntTools_Tools::IntermediatePoint(aT1, aT2);
740     }
741     aC3D->D0(aT, aP3D);
742   }
743   //
744   aState=BOPTools_AlgoTools::ComputeState(aP3D, theRef, theTol,
745                                           theContext);
746   //
747   return aState;
748 }
749 //=======================================================================
750 // function:  ComputeState
751 // purpose:
752 //=======================================================================
ComputeState(const gp_Pnt & theP,const TopoDS_Solid & theRef,const Standard_Real theTol,const Handle (IntTools_Context)& theContext)753 TopAbs_State BOPTools_AlgoTools::ComputeState
754   (const gp_Pnt& theP,
755    const TopoDS_Solid& theRef,
756    const Standard_Real theTol,
757    const Handle(IntTools_Context)& theContext)
758 {
759   TopAbs_State aState;
760   //
761   BRepClass3d_SolidClassifier& aSC=theContext->SolidClassifier(theRef);
762   aSC.Perform(theP, theTol);
763   //
764   aState=aSC.State();
765   //
766   return aState;
767 }
768 //=======================================================================
769 //function : IsInternalFace
770 //purpose  :
771 //=======================================================================
IsInternalFace(const TopoDS_Face & theFace,const TopoDS_Solid & theSolid,TopTools_IndexedDataMapOfShapeListOfShape & theMEF,const Standard_Real theTol,const Handle (IntTools_Context)& theContext)772 Standard_Boolean BOPTools_AlgoTools::IsInternalFace
773   (const TopoDS_Face& theFace,
774    const TopoDS_Solid& theSolid,
775    TopTools_IndexedDataMapOfShapeListOfShape& theMEF,
776    const Standard_Real theTol,
777    const Handle(IntTools_Context)& theContext)
778 {
779   Standard_Boolean bDegenerated;
780   TopAbs_Orientation aOr;
781   TopoDS_Edge aE1;
782   TopExp_Explorer aExp;
783   TopTools_ListIteratorOfListOfShape aItF;
784   //
785   // For all invoked functions: [::IsInternalFace(...)]
786   // the returned value iRet means:
787   // iRet=0;  - state is not IN
788   // iRet=1;  - state is IN
789   // iRet=2;  - state can not be found by the method of angles
790   Standard_Integer iRet = 0;
791   // 1 Try to find an edge from theFace in theMEF
792   aExp.Init(theFace, TopAbs_EDGE);
793   for(; aExp.More(); aExp.Next()) {
794     const TopoDS_Edge& aE=(*(TopoDS_Edge*)(&aExp.Current()));
795     if (!theMEF.Contains(aE)) {
796       continue;
797     }
798     //
799     aOr=aE.Orientation();
800     if (aOr==TopAbs_INTERNAL) {
801       continue;
802     }
803     bDegenerated=BRep_Tool::Degenerated(aE);
804     if (bDegenerated){
805       continue;
806     }
807     // aE
808     TopTools_ListOfShape& aLF=theMEF.ChangeFromKey(aE);
809     Standard_Integer aNbF = aLF.Extent();
810     if (aNbF==1) {
811       // aE is internal edge on aLF.First()
812       const TopoDS_Face& aF1=(*(TopoDS_Face*)(&aLF.First()));
813       BOPTools_AlgoTools::GetEdgeOnFace(aE, aF1, aE1);
814       if (aE1.Orientation() != TopAbs_INTERNAL) {
815         continue;
816       }
817       //
818       iRet=BOPTools_AlgoTools::IsInternalFace(theFace, aE, aF1, aF1,
819                                               theContext);
820       break;
821     }
822     //
823     else if (aNbF==2) {
824       const TopoDS_Face& aF1=(*(TopoDS_Face*)(&aLF.First()));
825       const TopoDS_Face& aF2=(*(TopoDS_Face*)(&aLF.Last()));
826       iRet=BOPTools_AlgoTools::IsInternalFace(theFace, aE, aF1, aF2,
827                                               theContext);
828       if (iRet != 2)
829         break;
830     }
831   }//for(; aExp.More(); aExp.Next()) {
832   //
833   if (aExp.More() && iRet != 2)
834   {
835     return iRet == 1;
836   }
837   //
838   //========================================
839   // 2. Classify face using classifier
840   //
841   TopAbs_State aState;
842   TopTools_IndexedMapOfShape aBounds;
843   //
844   TopExp::MapShapes(theSolid, TopAbs_EDGE, aBounds);
845   //
846   aState=BOPTools_AlgoTools::ComputeState(theFace, theSolid,
847                                           theTol, aBounds, theContext);
848   return aState == TopAbs_IN;
849 }
850 //=======================================================================
851 //function : IsInternalFace
852 //purpose  :
853 //=======================================================================
IsInternalFace(const TopoDS_Face & theFace,const TopoDS_Edge & theEdge,TopTools_ListOfShape & theLF,const Handle (IntTools_Context)& theContext)854 Standard_Integer BOPTools_AlgoTools::IsInternalFace
855   (const TopoDS_Face& theFace,
856    const TopoDS_Edge& theEdge,
857    TopTools_ListOfShape& theLF,
858    const Handle(IntTools_Context)& theContext)
859 {
860   Standard_Integer aNbF, iRet;
861   //
862   iRet=0;
863   //
864   aNbF=theLF.Extent();
865   if (aNbF==2) {
866     const TopoDS_Face& aF1=(*(TopoDS_Face*)(&theLF.First()));
867     const TopoDS_Face& aF2=(*(TopoDS_Face*)(&theLF.Last()));
868     iRet=BOPTools_AlgoTools::IsInternalFace(theFace, theEdge, aF1, aF2,
869                                             theContext);
870     return iRet;
871   }
872   //
873   else {
874     BOPTools_ListOfCoupleOfShape aLCFF;
875     BOPTools_ListIteratorOfListOfCoupleOfShape aIt;
876     //
877     FindFacePairs(theEdge, theLF, aLCFF, theContext);
878     //
879     aIt.Initialize(aLCFF);
880     for (; aIt.More(); aIt.Next()) {
881       BOPTools_CoupleOfShape& aCSFF=aIt.ChangeValue();
882       //
883       const TopoDS_Face& aF1=(*(TopoDS_Face*)(&aCSFF.Shape1()));
884       const TopoDS_Face& aF2=(*(TopoDS_Face*)(&aCSFF.Shape2()));
885       iRet=BOPTools_AlgoTools::IsInternalFace(theFace, theEdge, aF1, aF2,
886                                               theContext);
887       if (iRet) {
888         return iRet;
889       }
890     }
891   }
892   return iRet;
893 }
894 //=======================================================================
895 //function : IsInternalFace
896 //purpose  :
897 //=======================================================================
IsInternalFace(const TopoDS_Face & theFace,const TopoDS_Edge & theEdge,const TopoDS_Face & theFace1,const TopoDS_Face & theFace2,const Handle (IntTools_Context)& theContext)898 Standard_Integer BOPTools_AlgoTools::IsInternalFace
899   (const TopoDS_Face& theFace,
900    const TopoDS_Edge& theEdge,
901    const TopoDS_Face& theFace1,
902    const TopoDS_Face& theFace2,
903    const Handle(IntTools_Context)& theContext)
904 {
905   TopoDS_Edge aE1, aE2;
906   TopoDS_Face aFOff;
907   BOPTools_ListOfCoupleOfShape theLCSOff;
908   BOPTools_CoupleOfShape aCS1, aCS2;
909   //
910   BOPTools_AlgoTools::GetEdgeOnFace(theEdge, theFace1, aE1);
911   if (aE1.Orientation()==TopAbs_INTERNAL) {
912     aE2=aE1;
913     aE1.Orientation(TopAbs_FORWARD);
914     aE2.Orientation(TopAbs_REVERSED);
915   }
916   else if (theFace1==theFace2) {
917     aE2=aE1;
918     aE1.Orientation(TopAbs_FORWARD);
919     aE2.Orientation(TopAbs_REVERSED);
920   }
921   else {
922     BOPTools_AlgoTools::GetEdgeOnFace(theEdge, theFace2, aE2);
923   }
924   //
925   aCS1.SetShape1(theEdge);
926   aCS1.SetShape2(theFace);
927   theLCSOff.Append(aCS1);
928   //
929   aCS2.SetShape1(aE2);
930   aCS2.SetShape2(theFace2);
931   theLCSOff.Append(aCS2);
932   //
933   Standard_Integer iRet = 0; // theFace is not internal
934   Standard_Boolean isDone = GetFaceOff (aE1, theFace1, theLCSOff, aFOff, theContext);
935   if (!isDone)
936     // error, unable to classify face by this edge
937     iRet = 2;
938   else if (theFace.IsEqual (aFOff))
939     // theFace is internal
940     iRet = 1;
941 
942   return iRet;
943 }
944 //=======================================================================
945 //function : GetFaceOff
946 //purpose  :
947 //=======================================================================
GetFaceOff(const TopoDS_Edge & theE1,const TopoDS_Face & theF1,BOPTools_ListOfCoupleOfShape & theLCSOff,TopoDS_Face & theFOff,const Handle (IntTools_Context)& theContext)948 Standard_Boolean BOPTools_AlgoTools::GetFaceOff
949   (const TopoDS_Edge& theE1,
950    const TopoDS_Face& theF1,
951    BOPTools_ListOfCoupleOfShape& theLCSOff,
952    TopoDS_Face& theFOff,
953    const Handle(IntTools_Context)& theContext)
954 {
955   Standard_Boolean bRet, bIsComputed;
956   Standard_Real aT, aT1, aT2, aAngle, aTwoPI, aAngleMin, aDt3D;
957   Standard_Real aUmin, aUsup, aVmin, aVsup;
958   gp_Pnt aPn1, aPn2, aPx;
959   gp_Dir aDN1, aDN2, aDBF, aDBF2, aDTF;
960   gp_Vec aVTgt;
961   TopAbs_Orientation aOr;
962   Handle(Geom_Curve)aC3D;
963   Handle(Geom_Plane) aPL;
964   BOPTools_ListIteratorOfListOfCoupleOfShape aIt;
965   GeomAPI_ProjectPointOnSurf aProjPL;
966   //
967   aAngleMin=100.;
968   aTwoPI=M_PI+M_PI;
969   aC3D =BRep_Tool::Curve(theE1, aT1, aT2);
970   aT=BOPTools_AlgoTools2D::IntermediatePoint(aT1, aT2);
971   aC3D->D0(aT, aPx);
972   //
973   BOPTools_AlgoTools2D::EdgeTangent(theE1, aT, aVTgt);
974   gp_Dir aDTgt(aVTgt), aDTgt2;
975   aOr = theE1.Orientation();
976   //
977   aPL = new Geom_Plane(aPx, aDTgt);
978   aPL->Bounds(aUmin, aUsup, aVmin, aVsup);
979   aProjPL.Init(aPL, aUmin, aUsup, aVmin, aVsup);
980   //
981   Standard_Boolean bSmallFaces = Standard_False;
982   aDt3D = MinStep3D(theE1, theF1, theLCSOff, aPx, theContext, bSmallFaces);
983   bIsComputed = GetFaceDir(theE1, theF1, aPx, aT, aDTgt, bSmallFaces,
984                            aDN1, aDBF, theContext, aProjPL, aDt3D);
985   if (!bIsComputed) {
986 #ifdef OCCT_DEBUG
987     std::cout << "BOPTools_AlgoTools::GetFaceOff(): incorrect computation of bi-normal direction." << std::endl;
988 #endif
989   }
990   //
991   aDTF=aDN1^aDBF;
992   //
993   // The difference between faces should be obvious enough
994   // to guarantee the correctness of the classification
995   Standard_Real anAngleCriteria = Precision::Confusion();
996 
997   bRet=Standard_True;
998   aIt.Initialize(theLCSOff);
999   for (; aIt.More(); aIt.Next()) {
1000     const BOPTools_CoupleOfShape& aCS=aIt.Value();
1001     const TopoDS_Edge& aE2=(*(TopoDS_Edge*)(&aCS.Shape1()));
1002     const TopoDS_Face& aF2=(*(TopoDS_Face*)(&aCS.Shape2()));
1003     //
1004     aDTgt2 = (aE2.Orientation()==aOr) ? aDTgt : aDTgt.Reversed();
1005     bIsComputed = GetFaceDir(aE2, aF2, aPx, aT, aDTgt2, bSmallFaces, aDN2,
1006                              aDBF2, theContext, aProjPL, aDt3D);
1007     if (!bIsComputed) {
1008 #ifdef OCCT_DEBUG
1009       std::cout << "BOPTools_AlgoTools::GetFaceOff(): incorrect computation of bi-normal direction." << std::endl;
1010 #endif
1011     }
1012     //Angle
1013     aAngle=AngleWithRef(aDBF, aDBF2, aDTF);
1014     //
1015     if (Abs(aAngle) < Precision::Angular()) {
1016       if (aF2==theF1) {
1017         aAngle=M_PI;
1018       }
1019       else if (aF2.IsSame(theF1)) {
1020         aAngle=aTwoPI;
1021       }
1022     }
1023     //
1024     if (Abs(aAngle) < anAngleCriteria ||
1025         Abs (aAngle-aAngleMin) < anAngleCriteria) {
1026       // the minimal angle can not be found
1027       bRet=Standard_False;
1028     }
1029     //
1030     if (aAngle < 0.)
1031     {
1032       aAngle = aTwoPI + aAngle;
1033     }
1034     //
1035     if (aAngle<aAngleMin){
1036       aAngleMin=aAngle;
1037       theFOff=aF2;
1038     }
1039   }
1040   return bRet;
1041 }
1042 //=======================================================================
1043 //function : GetEdgeOff
1044 //purpose  :
1045 //=======================================================================
GetEdgeOff(const TopoDS_Edge & theE1,const TopoDS_Face & theF2,TopoDS_Edge & theE2)1046 Standard_Boolean BOPTools_AlgoTools::GetEdgeOff(const TopoDS_Edge& theE1,
1047                                                 const TopoDS_Face& theF2,
1048                                                 TopoDS_Edge& theE2)
1049 {
1050   Standard_Boolean bFound;
1051   TopAbs_Orientation aOr1, aOr1C, aOr2;
1052   TopExp_Explorer anExp;
1053   //
1054   bFound=Standard_False;
1055   aOr1=theE1.Orientation();
1056   aOr1C=TopAbs::Reverse(aOr1);
1057   //
1058   anExp.Init(theF2, TopAbs_EDGE);
1059   for (; anExp.More(); anExp.Next()) {
1060     const TopoDS_Edge& aEF2=(*(TopoDS_Edge*)(&anExp.Current()));
1061     if (aEF2.IsSame(theE1)) {
1062       aOr2=aEF2.Orientation();
1063       if (aOr2==aOr1C) {
1064         theE2=aEF2;
1065         bFound=!bFound;
1066         return bFound;
1067       }
1068     }
1069   }
1070   return bFound;
1071 }
1072 
1073 //=======================================================================
1074 //function : AreFacesSameDomain
1075 //purpose  :
1076 //=======================================================================
AreFacesSameDomain(const TopoDS_Face & theF1,const TopoDS_Face & theF2,const Handle (IntTools_Context)& theContext,const Standard_Real theFuzz)1077 Standard_Boolean BOPTools_AlgoTools::AreFacesSameDomain
1078   (const TopoDS_Face& theF1,
1079    const TopoDS_Face& theF2,
1080    const Handle(IntTools_Context)& theContext,
1081    const Standard_Real theFuzz)
1082 {
1083   Standard_Boolean bFacesSD = Standard_False;
1084 
1085   // The idea is to find a point inside the first face
1086   // and check its validity for the second face.
1087   // If valid - the faces are same domain.
1088 
1089   gp_Pnt aP1;
1090   gp_Pnt2d aP2D1;
1091   // Find point inside the first face
1092   Standard_Integer iErr =
1093     BOPTools_AlgoTools3D::PointInFace(theF1, aP1, aP2D1, theContext);
1094 
1095   if (iErr != 0)
1096   {
1097     // unable to find the point
1098     return bFacesSD;
1099   }
1100 
1101   // Check validity of the point for second face
1102 
1103   // Compute the tolerance to check the validity -
1104   // sum of tolerance of faces and fuzzy tolerance
1105 
1106   // Compute the tolerance of the faces, taking into account the deviation
1107   // of the edges from the surfaces
1108   Standard_Real aTolF1 = BRep_Tool::Tolerance(theF1),
1109                 aTolF2 = BRep_Tool::Tolerance(theF2);
1110 
1111   // Find maximal tolerance of edges.
1112   // The faces should have the same boundaries, thus
1113   // it does not matter which face to explore.
1114   {
1115     Standard_Real aTolEMax = -1.;
1116     TopExp_Explorer anExpE(theF1, TopAbs_EDGE);
1117     for (; anExpE.More(); anExpE.Next())
1118     {
1119       const TopoDS_Edge& aE = TopoDS::Edge(anExpE.Current());
1120       if (!BRep_Tool::Degenerated(aE))
1121       {
1122         Standard_Real aTolE = BRep_Tool::Tolerance(aE);
1123         if (aTolE > aTolEMax)
1124           aTolEMax = aTolE;
1125       }
1126     }
1127     if (aTolEMax > aTolF1) aTolF1 = aTolEMax;
1128     if (aTolEMax > aTolF2) aTolF2 = aTolEMax;
1129   }
1130 
1131   // Checking criteria
1132   Standard_Real aTol = aTolF1 + aTolF2 + Max(theFuzz, Precision::Confusion());
1133 
1134   // Project and classify the point on second face
1135   bFacesSD = theContext->IsValidPointForFace(aP1, theF2, aTol);
1136 
1137   return bFacesSD;
1138 }
1139 
1140 //=======================================================================
1141 // function: Sense
1142 // purpose:
1143 //=======================================================================
Sense(const TopoDS_Face & theF1,const TopoDS_Face & theF2,const Handle (IntTools_Context)& theContext)1144 Standard_Integer BOPTools_AlgoTools::Sense(const TopoDS_Face& theF1,
1145                                            const TopoDS_Face& theF2,
1146                                            const Handle(IntTools_Context)& theContext)
1147 {
1148   Standard_Integer iSense=0;
1149   gp_Dir aDNF1, aDNF2;
1150   TopoDS_Edge aE1, aE2;
1151   TopExp_Explorer aExp;
1152   //
1153   aExp.Init(theF1, TopAbs_EDGE);
1154   for (; aExp.More(); aExp.Next()) {
1155     aE1=(*(TopoDS_Edge*)(&aExp.Current()));
1156     if (!BRep_Tool::Degenerated(aE1)) {
1157       if (!BRep_Tool::IsClosed(aE1, theF1)) {
1158         break;
1159       }
1160     }
1161   }
1162   //
1163   aExp.Init(theF2, TopAbs_EDGE);
1164   for (; aExp.More(); aExp.Next()) {
1165     aE2=(*(TopoDS_Edge*)(&aExp.Current()));
1166     if (!BRep_Tool::Degenerated(aE2)) {
1167       if (!BRep_Tool::IsClosed(aE2, theF2)) {
1168         if (aE2.IsSame(aE1)) {
1169           iSense=1;
1170           break;
1171         }
1172       }
1173     }
1174   }
1175   //
1176   if (!iSense) {
1177     return iSense;
1178   }
1179   //
1180   BOPTools_AlgoTools3D::GetNormalToFaceOnEdge(aE1, theF1, aDNF1, theContext);
1181   BOPTools_AlgoTools3D::GetNormalToFaceOnEdge(aE2, theF2, aDNF2, theContext);
1182   //
1183   iSense=BOPTools_AlgoTools3D::SenseFlag(aDNF1, aDNF2);
1184   //
1185   return iSense;
1186 }
1187 //=======================================================================
1188 // function: IsSplitToReverse
1189 // purpose:
1190 //=======================================================================
IsSplitToReverse(const TopoDS_Shape & theSp,const TopoDS_Shape & theSr,const Handle (IntTools_Context)& theContext,Standard_Integer * theError)1191 Standard_Boolean BOPTools_AlgoTools::IsSplitToReverse
1192   (const TopoDS_Shape& theSp,
1193    const TopoDS_Shape& theSr,
1194    const Handle(IntTools_Context)& theContext,
1195    Standard_Integer *theError)
1196 {
1197   Standard_Boolean bRet;
1198   TopAbs_ShapeEnum aType;
1199   //
1200   bRet=Standard_False;
1201   //
1202   aType=theSp.ShapeType();
1203   switch (aType) {
1204     case TopAbs_EDGE: {
1205       const TopoDS_Edge& aESp=(*(TopoDS_Edge*)(&theSp));
1206       const TopoDS_Edge& aESr=(*(TopoDS_Edge*)(&theSr));
1207       bRet=BOPTools_AlgoTools::IsSplitToReverse(aESp, aESr, theContext, theError);
1208     }
1209       break;
1210       //
1211     case TopAbs_FACE: {
1212       const TopoDS_Face& aFSp=(*(TopoDS_Face*)(&theSp));
1213       const TopoDS_Face& aFSr=(*(TopoDS_Face*)(&theSr));
1214       bRet=BOPTools_AlgoTools::IsSplitToReverse(aFSp, aFSr, theContext, theError);
1215     }
1216       break;
1217       //
1218     default:
1219       if (theError)
1220         *theError = 100;
1221       break;
1222   }
1223   return bRet;
1224 }
1225 
1226 //=======================================================================
1227 //function : IsSplitToReverseWithWarn
1228 //purpose  :
1229 //=======================================================================
IsSplitToReverseWithWarn(const TopoDS_Shape & theSplit,const TopoDS_Shape & theShape,const Handle (IntTools_Context)& theContext,const Handle (Message_Report)& theReport)1230 Standard_Boolean BOPTools_AlgoTools::IsSplitToReverseWithWarn(const TopoDS_Shape& theSplit,
1231                                                               const TopoDS_Shape& theShape,
1232                                                               const Handle(IntTools_Context)& theContext,
1233                                                               const Handle(Message_Report)& theReport)
1234 {
1235   Standard_Integer anErr;
1236   Standard_Boolean isToReverse = BOPTools_AlgoTools::IsSplitToReverse(theSplit, theShape, theContext, &anErr);
1237   if (anErr != 0 && !theReport.IsNull())
1238   {
1239     // The error occurred during the check.
1240     // Add warning to the report, storing the shapes into the warning.
1241     TopoDS_Compound aWC;
1242     BRep_Builder().MakeCompound(aWC);
1243     BRep_Builder().Add(aWC, theSplit);
1244     BRep_Builder().Add(aWC, theShape);
1245     theReport->AddAlert(Message_Warning, new BOPAlgo_AlertUnableToOrientTheShape(aWC));
1246   }
1247   return isToReverse;
1248 }
1249 
1250 //=======================================================================
1251 //function :IsSplitToReverse
1252 //purpose  :
1253 //=======================================================================
IsSplitToReverse(const TopoDS_Face & theFSp,const TopoDS_Face & theFSr,const Handle (IntTools_Context)& theContext,Standard_Integer * theError)1254 Standard_Boolean BOPTools_AlgoTools::IsSplitToReverse
1255   (const TopoDS_Face& theFSp,
1256    const TopoDS_Face& theFSr,
1257    const Handle(IntTools_Context)& theContext,
1258    Standard_Integer *theError)
1259 {
1260   // Set OK error status
1261   if (theError)
1262     *theError = 0;
1263 
1264   // Compare surfaces
1265   Handle(Geom_Surface) aSFSp = BRep_Tool::Surface(theFSp);
1266   Handle(Geom_Surface) aSFOr = BRep_Tool::Surface(theFSr);
1267   if (aSFSp == aSFOr) {
1268     return theFSp.Orientation() != theFSr.Orientation();
1269   }
1270   //
1271   Standard_Boolean bDone = Standard_False;
1272   // Find the point inside the split face
1273   gp_Pnt aPFSp;
1274   gp_Pnt2d aP2DFSp;
1275   //
1276   // Error status
1277   Standard_Integer iErr;
1278   // Use the hatcher to find the point in the middle of the face
1279   iErr = BOPTools_AlgoTools3D::PointInFace(theFSp, aPFSp, aP2DFSp, theContext);
1280   if (iErr) {
1281     // Hatcher has failed to find a point.
1282     // Try to get the point near some not closed and
1283     // not degenerated edge on the split face.
1284     TopExp_Explorer anExp(theFSp, TopAbs_EDGE);
1285     for (; anExp.More(); anExp.Next()) {
1286       const TopoDS_Edge& aESp = (*(TopoDS_Edge*)(&anExp.Current()));
1287       if (!BRep_Tool::Degenerated(aESp) && !BRep_Tool::IsClosed(aESp, theFSp)) {
1288         iErr = BOPTools_AlgoTools3D::PointNearEdge
1289                  (aESp, theFSp, aP2DFSp, aPFSp, theContext);
1290         if (!iErr) {
1291           break;
1292         }
1293       }
1294     }
1295     //
1296     if (!anExp.More()) {
1297       if (theError)
1298         *theError = 1;
1299       // The point has not been found.
1300       return bDone;
1301     }
1302   }
1303   //
1304   // Compute normal direction of the split face
1305   gp_Dir aDNFSp;
1306   bDone = BOPTools_AlgoTools3D::GetNormalToSurface
1307     (aSFSp, aP2DFSp.X(), aP2DFSp.Y(), aDNFSp);
1308   if (!bDone) {
1309     if (theError)
1310       *theError = 2;
1311     return bDone;
1312   }
1313   //
1314   if (theFSp.Orientation() == TopAbs_REVERSED){
1315     aDNFSp.Reverse();
1316   }
1317   //
1318   // Project the point from the split face on the original face
1319   // to find its UV coordinates
1320   GeomAPI_ProjectPointOnSurf& aProjector = theContext->ProjPS(theFSr);
1321   aProjector.Perform(aPFSp);
1322   bDone = (aProjector.NbPoints() > 0);
1323   if (!bDone) {
1324     if (theError)
1325       *theError = 3;
1326     return bDone;
1327   }
1328   // UV coordinates of the point on the original face
1329   Standard_Real aU, aV;
1330   aProjector.LowerDistanceParameters(aU, aV);
1331   //
1332   // Compute normal direction for the original face in this point
1333   gp_Dir aDNFOr;
1334   bDone = BOPTools_AlgoTools3D::GetNormalToSurface(aSFOr, aU, aV, aDNFOr);
1335   if (!bDone) {
1336     if (theError)
1337       *theError = 4;
1338     return bDone;
1339   }
1340   //
1341   if (theFSr.Orientation() == TopAbs_REVERSED) {
1342     aDNFOr.Reverse();
1343   }
1344   //
1345   // compare the normals
1346   Standard_Real aCos = aDNFSp*aDNFOr;
1347   return (aCos < 0.);
1348 }
1349 //=======================================================================
1350 //function :IsSplitToReverse
1351 //purpose  :
1352 //=======================================================================
IsSplitToReverse(const TopoDS_Edge & theESp,const TopoDS_Edge & theEOr,const Handle (IntTools_Context)& theContext,Standard_Integer * theError)1353 Standard_Boolean BOPTools_AlgoTools::IsSplitToReverse
1354   (const TopoDS_Edge& theESp,
1355    const TopoDS_Edge& theEOr,
1356    const Handle(IntTools_Context)& theContext,
1357    Standard_Integer *theError)
1358 {
1359   // The idea is to compare the tangent vectors of two edges computed in
1360   // the same point. Thus, we need to take the point on split edge (since it is
1361   // shorter) and project it onto original edge to find corresponding parameter.
1362 
1363   if (BRep_Tool::Degenerated(theESp) ||
1364       BRep_Tool::Degenerated(theEOr))
1365   {
1366     if (theError)
1367       *theError = 1;
1368     return Standard_False;
1369   }
1370 
1371   // Set OK error status
1372   if (theError)
1373     *theError = 0;
1374 
1375   // Get the curves from the edges
1376   Standard_Real f, l;
1377   Handle(Geom_Curve) aCSp = BRep_Tool::Curve(theESp, f, l);
1378   Handle(Geom_Curve) aCOr = BRep_Tool::Curve(theEOr, f, l);
1379 
1380   // If the curves are the same, compare orientations only
1381   if (aCSp == aCOr)
1382     return theESp.Orientation() != theEOr.Orientation();
1383 
1384   // Find valid range of the split edge, to ensure that the point for computing
1385   // tangent vectors will be inside both edges.
1386   if (!BRepLib::FindValidRange(theESp, f, l))
1387     BRep_Tool::Range(theESp, f, l);
1388 
1389   // Error code
1390   Standard_Integer anErr = 0;
1391   // Try a few sample points on the split edge until first valid found
1392   const Standard_Integer aNbP = 11;
1393   const Standard_Real aDT = (l - f) / aNbP;
1394   for (Standard_Integer i = 1; i < aNbP; ++i)
1395   {
1396     const Standard_Real aTm = f + i*aDT;
1397     // Compute tangent vector on split edge
1398     gp_Vec aVSpTgt;
1399     if (!BOPTools_AlgoTools2D::EdgeTangent(theESp, aTm, aVSpTgt))
1400     {
1401       // Unable to compute the tangent vector on the split edge
1402       // in this point -> take the next point
1403       anErr = 2;
1404       continue;
1405     }
1406 
1407     // Find corresponding parameter on the original edge
1408     Standard_Real aTmOr;
1409     if (!theContext->ProjectPointOnEdge(aCSp->Value(aTm), theEOr, aTmOr))
1410     {
1411       // Unable to project the point inside the split edge
1412       // onto the original edge -> take the next point
1413       anErr = 3;
1414       continue;
1415     }
1416 
1417     // Compute tangent vector on original edge
1418     gp_Vec aVOrTgt;
1419     if (!BOPTools_AlgoTools2D::EdgeTangent(theEOr, aTmOr, aVOrTgt))
1420     {
1421       // Unable to compute the tangent vector on the original edge
1422       // in this point -> take the next point
1423       anErr = 4;
1424       continue;
1425     }
1426 
1427     // Compute the Dot product
1428     Standard_Real aCos = aVSpTgt.Dot(aVOrTgt);
1429     return (aCos < 0.);
1430   }
1431 
1432   if (theError)
1433     *theError = anErr;
1434 
1435   return Standard_False;
1436 }
1437 
1438 //=======================================================================
1439 //function : IsHole
1440 //purpose  :
1441 //=======================================================================
IsHole(const TopoDS_Shape & aW,const TopoDS_Shape & aFace)1442 Standard_Boolean BOPTools_AlgoTools::IsHole(const TopoDS_Shape& aW,
1443                                             const TopoDS_Shape& aFace)
1444 {
1445   Standard_Boolean bIsHole;
1446   Standard_Integer i, aNbS;
1447   Standard_Real aT1, aT2, aS;
1448   Standard_Real aU1, aU, dU;
1449   Standard_Real aX1, aY1, aX0, aY0;
1450   TopAbs_Orientation aOr;
1451 
1452   gp_Pnt2d aP2D0, aP2D1;
1453   Handle(Geom2d_Curve) aC2D;
1454   TopoDS_Face aF, aFF;
1455   TopoDS_Iterator aItW;
1456   //
1457   bIsHole=Standard_False;
1458   //
1459   aF=(*(TopoDS_Face *)(&aFace));
1460   aFF=aF;
1461   aFF.Orientation(TopAbs_FORWARD);
1462   //
1463   aS=0.;
1464   aItW.Initialize(aW);
1465   for (; aItW.More(); aItW.Next()) {
1466     const TopoDS_Edge& aE=(*(TopoDS_Edge *)(&aItW.Value()));
1467     aOr=aE.Orientation();
1468     if (!(aOr==TopAbs_FORWARD ||
1469           aOr==TopAbs_REVERSED)) {
1470       continue;
1471     }
1472     //
1473     aC2D=BRep_Tool::CurveOnSurface(aE, aFF, aT1, aT2);
1474     if (aC2D.IsNull()) {
1475       break; //xx
1476     }
1477     //
1478     BRepAdaptor_Curve2d aBAC2D(aE, aFF);
1479     aNbS=Geom2dInt_Geom2dCurveTool::NbSamples(aBAC2D);
1480     if (aNbS>2) {
1481       aNbS*=4;
1482     }
1483     //
1484     dU=(aT2-aT1)/(Standard_Real)(aNbS-1);
1485     aU =aT1;
1486     aU1=aT1;
1487     if (aOr==TopAbs_REVERSED) {
1488       aU =aT2;
1489       aU1=aT2;
1490       dU=-dU;
1491     }
1492     //
1493     aBAC2D.D0(aU, aP2D0);
1494     for(i=2; i<=aNbS; i++) {
1495       aU=aU1+(i-1)*dU;
1496       aBAC2D.D0(aU, aP2D1);
1497       aP2D0.Coord(aX0, aY0);
1498       aP2D1.Coord(aX1, aY1);
1499       //
1500       aS=aS+(aY0+aY1)*(aX1-aX0);
1501       //
1502       aP2D0=aP2D1;
1503     }
1504   }//for (; aItW.More(); aItW.Next()) {
1505   bIsHole=(aS>0.);
1506   return bIsHole;
1507 }
1508 
1509 //=======================================================================
1510 // function: MakeContainer
1511 // purpose:
1512 //=======================================================================
MakeContainer(const TopAbs_ShapeEnum theType,TopoDS_Shape & theC)1513 void BOPTools_AlgoTools::MakeContainer(const TopAbs_ShapeEnum theType,
1514                                        TopoDS_Shape& theC)
1515 {
1516   BRep_Builder aBB;
1517   //
1518   switch(theType) {
1519     case TopAbs_COMPOUND:{
1520       TopoDS_Compound aC;
1521       aBB.MakeCompound(aC);
1522       theC=aC;
1523     }
1524       break;
1525       //
1526     case TopAbs_COMPSOLID:{
1527       TopoDS_CompSolid aCS;
1528       aBB.MakeCompSolid(aCS);
1529       theC=aCS;
1530     }
1531       break;
1532       //
1533     case TopAbs_SOLID:{
1534       TopoDS_Solid aSolid;
1535       aBB.MakeSolid(aSolid);
1536       theC=aSolid;
1537     }
1538       break;
1539       //
1540       //
1541     case TopAbs_SHELL:{
1542       TopoDS_Shell aShell;
1543       aBB.MakeShell(aShell);
1544       theC=aShell;
1545     }
1546       break;
1547       //
1548     case TopAbs_WIRE: {
1549       TopoDS_Wire aWire;
1550       aBB.MakeWire(aWire);
1551       theC=aWire;
1552     }
1553       break;
1554       //
1555     default:
1556       break;
1557   }
1558 }
1559 //=======================================================================
1560 // function: MakePCurve
1561 // purpose:
1562 //=======================================================================
MakePCurve(const TopoDS_Edge & aE,const TopoDS_Face & aF1,const TopoDS_Face & aF2,const IntTools_Curve & aIC,const Standard_Boolean bPC1,const Standard_Boolean bPC2,const Handle (IntTools_Context)& theContext)1563 void BOPTools_AlgoTools::MakePCurve(const TopoDS_Edge& aE,
1564                                     const TopoDS_Face& aF1,
1565                                     const TopoDS_Face& aF2,
1566                                     const IntTools_Curve& aIC,
1567                                     const Standard_Boolean bPC1,
1568                                     const Standard_Boolean bPC2,
1569                                     const Handle(IntTools_Context)& theContext)
1570 
1571 {
1572   Standard_Integer i;
1573   Standard_Real aTolE, aT1, aT2, aOutFirst, aOutLast, aOutTol;
1574   Handle(Geom2d_Curve) aC2D, aC2DA, aC2Dx1;
1575   TopoDS_Face aFFWD;
1576   BRep_Builder aBB;
1577   Standard_Boolean bPC;
1578   //
1579   aTolE=BRep_Tool::Tolerance(aE);
1580   //
1581   const Handle(Geom_Curve)& aC3DE=BRep_Tool::Curve(aE, aT1, aT2);
1582   Handle(Geom_TrimmedCurve)aC3DETrim=
1583     new Geom_TrimmedCurve(aC3DE, aT1, aT2);
1584   //
1585   for (i=0; i<2; ++i) {
1586     bPC = !i ? bPC1 : bPC2;
1587     if (!bPC) {
1588       continue;
1589     }
1590     //
1591     if (!i) {
1592       aFFWD=aF1;
1593       aC2Dx1=aIC.FirstCurve2d();
1594     }
1595     else {
1596       aFFWD=aF2;
1597       aC2Dx1=aIC.SecondCurve2d();
1598     }
1599     //
1600     aFFWD.Orientation(TopAbs_FORWARD);
1601     //
1602     aC2D=aC2Dx1;
1603     if (aC2D.IsNull()) {
1604       BOPTools_AlgoTools2D::BuildPCurveForEdgeOnFace(aE, aFFWD, theContext);
1605       BOPTools_AlgoTools2D::CurveOnSurface(aE, aFFWD, aC2D,
1606                                        aOutFirst, aOutLast,
1607                                        aOutTol, theContext);
1608       }
1609     //
1610     if (aC3DE->IsPeriodic()) {
1611       BOPTools_AlgoTools2D::AdjustPCurveOnFace(aFFWD, aT1, aT2,  aC2D,
1612                                                aC2DA, theContext);
1613     }
1614     else {
1615       BOPTools_AlgoTools2D::AdjustPCurveOnFace(aFFWD, aC3DETrim, aC2D,
1616                                                aC2DA, theContext);
1617     }
1618     //
1619     aBB.UpdateEdge(aE, aC2DA, aFFWD, aTolE);
1620     //BRepLib::SameParameter(aE);
1621   }
1622   BRepLib::SameParameter(aE);
1623 }
1624 //=======================================================================
1625 // function: MakeEdge
1626 // purpose:
1627 //=======================================================================
MakeEdge(const IntTools_Curve & theIC,const TopoDS_Vertex & theV1,const Standard_Real theT1,const TopoDS_Vertex & theV2,const Standard_Real theT2,const Standard_Real theTolR3D,TopoDS_Edge & theE)1628 void BOPTools_AlgoTools::MakeEdge(const IntTools_Curve& theIC,
1629                                   const TopoDS_Vertex& theV1,
1630                                   const Standard_Real theT1,
1631                                   const TopoDS_Vertex& theV2,
1632                                   const Standard_Real theT2,
1633                                   const Standard_Real theTolR3D,
1634                                   TopoDS_Edge& theE)
1635 {
1636   BRep_Builder aBB;
1637   Standard_Real aNeedTol = theTolR3D + BOPTools_AlgoTools::DTolerance();
1638   //
1639   aBB.UpdateVertex(theV1, aNeedTol);
1640   aBB.UpdateVertex(theV2, aNeedTol);
1641   //
1642   BOPTools_AlgoTools::MakeSectEdge (theIC, theV1, theT1, theV2, theT2,
1643                                     theE);
1644   //
1645   aBB.UpdateEdge(theE, theTolR3D);
1646 }
1647 //=======================================================================
1648 // function: ComputeVV
1649 // purpose:
1650 //=======================================================================
ComputeVV(const TopoDS_Vertex & aV1,const gp_Pnt & aP2,const Standard_Real aTolP2)1651 Standard_Integer BOPTools_AlgoTools::ComputeVV(const TopoDS_Vertex& aV1,
1652                                                const gp_Pnt& aP2,
1653                                                const Standard_Real aTolP2)
1654 {
1655   Standard_Real aTolV1, aTolSum, aTolSum2, aD2;
1656   gp_Pnt aP1;
1657   //
1658   aTolV1=BRep_Tool::Tolerance(aV1);
1659 
1660   aTolSum = aTolV1 + aTolP2 + Precision::Confusion();
1661   aTolSum2=aTolSum*aTolSum;
1662   //
1663   aP1=BRep_Tool::Pnt(aV1);
1664   //
1665   aD2=aP1.SquareDistance(aP2);
1666   if (aD2>aTolSum2) {
1667     return 1;
1668   }
1669   return 0;
1670 }
1671 //=======================================================================
1672 // function: ComputeVV
1673 // purpose:
1674 //=======================================================================
ComputeVV(const TopoDS_Vertex & aV1,const TopoDS_Vertex & aV2,const Standard_Real aFuzz)1675 Standard_Integer BOPTools_AlgoTools::ComputeVV(const TopoDS_Vertex& aV1,
1676                                                const TopoDS_Vertex& aV2,
1677                                                const Standard_Real aFuzz)
1678 {
1679   Standard_Real aTolV1, aTolV2, aTolSum, aTolSum2, aD2;
1680   gp_Pnt aP1, aP2;
1681   Standard_Real aFuzz1 = (aFuzz > Precision::Confusion() ? aFuzz : Precision::Confusion());
1682   //
1683   aTolV1=BRep_Tool::Tolerance(aV1);
1684   aTolV2=BRep_Tool::Tolerance(aV2);
1685   aTolSum=aTolV1+aTolV2+aFuzz1;
1686   aTolSum2=aTolSum*aTolSum;
1687   //
1688   aP1=BRep_Tool::Pnt(aV1);
1689   aP2=BRep_Tool::Pnt(aV2);
1690   //
1691   aD2=aP1.SquareDistance(aP2);
1692   if (aD2>aTolSum2) {
1693     return 1;
1694   }
1695   return 0;
1696 }
1697 //=======================================================================
1698 // function: MakeVertex
1699 // purpose :
1700 //=======================================================================
MakeVertex(const TopTools_ListOfShape & aLV,TopoDS_Vertex & aVnew)1701 void BOPTools_AlgoTools::MakeVertex(const TopTools_ListOfShape& aLV,
1702                                     TopoDS_Vertex& aVnew)
1703 {
1704   Standard_Integer aNb = aLV.Extent();
1705   if (aNb == 1)
1706     aVnew=*((TopoDS_Vertex*)(&aLV.First()));
1707   else if (aNb > 1)
1708   {
1709     Standard_Real aNTol;
1710     gp_Pnt aNC;
1711     BRepLib::BoundingVertex(aLV, aNC, aNTol);
1712     BRep_Builder aBB;
1713     aBB.MakeVertex(aVnew, aNC, aNTol);
1714   }
1715 }
1716 //=======================================================================
1717 //function : GetEdgeOnFace
1718 //purpose  :
1719 //=======================================================================
GetEdgeOnFace(const TopoDS_Edge & theE1,const TopoDS_Face & theF2,TopoDS_Edge & theE2)1720 Standard_Boolean BOPTools_AlgoTools::GetEdgeOnFace
1721 (const TopoDS_Edge& theE1,
1722  const TopoDS_Face& theF2,
1723  TopoDS_Edge& theE2)
1724 {
1725   Standard_Boolean bFound;
1726   TopoDS_Iterator aItF, aItW;
1727   //
1728   bFound=Standard_False;
1729   //
1730   aItF.Initialize(theF2);
1731   for (; aItF.More(); aItF.Next()) {
1732     const TopoDS_Shape& aW=aItF.Value();
1733     aItW.Initialize(aW);
1734     for (; aItW.More(); aItW.Next()) {
1735       const TopoDS_Shape& aE=aItW.Value();
1736       if (aE.IsSame(theE1)) {
1737         theE2=(*(TopoDS_Edge*)(&aE));
1738         bFound=!bFound;
1739         return bFound;
1740       }
1741     }
1742   }
1743   return bFound;
1744 }
1745 //=======================================================================
1746 //function : FindFacePairs
1747 //purpose  :
1748 //=======================================================================
FindFacePairs(const TopoDS_Edge & theE,const TopTools_ListOfShape & thLF,BOPTools_ListOfCoupleOfShape & theLCFF,const Handle (IntTools_Context)& theContext)1749 Standard_Boolean FindFacePairs (const TopoDS_Edge& theE,
1750                                 const TopTools_ListOfShape& thLF,
1751                                 BOPTools_ListOfCoupleOfShape& theLCFF,
1752                                 const Handle(IntTools_Context)& theContext)
1753 {
1754   Standard_Boolean bFound;
1755   Standard_Integer i, aNbCEF;
1756   TopAbs_Orientation aOr, aOrC = TopAbs_FORWARD;
1757   TopTools_MapOfShape aMFP;
1758   TopoDS_Face aF1, aF2;
1759   TopoDS_Edge aEL, aE1;
1760   TopTools_ListIteratorOfListOfShape aItLF;
1761   BOPTools_CoupleOfShape aCEF, aCFF;
1762   BOPTools_ListOfCoupleOfShape aLCEF, aLCEFx;
1763   BOPTools_ListIteratorOfListOfCoupleOfShape aIt;
1764   //
1765   bFound=Standard_True;
1766   //
1767   // Preface aLCEF
1768   aItLF.Initialize(thLF);
1769   for (; aItLF.More(); aItLF.Next()) {
1770     const TopoDS_Face& aFL=(*(TopoDS_Face*)(&aItLF.Value()));
1771     //
1772     bFound=BOPTools_AlgoTools::GetEdgeOnFace(theE, aFL, aEL);
1773     if (!bFound) {
1774       return bFound; // it can not be so
1775     }
1776     //
1777     aCEF.SetShape1(aEL);
1778     aCEF.SetShape2(aFL);
1779     aLCEF.Append(aCEF);
1780   }
1781   //
1782   aNbCEF=aLCEF.Extent();
1783   while(aNbCEF) {
1784     //
1785     // aLCEFx
1786     aLCEFx.Clear();
1787     aIt.Initialize(aLCEF);
1788     for (i=0; aIt.More(); aIt.Next(), ++i) {
1789       const BOPTools_CoupleOfShape& aCSx=aIt.Value();
1790       const TopoDS_Shape& aEx=aCSx.Shape1();
1791       const TopoDS_Shape& aFx=aCSx.Shape2();
1792       //
1793       aOr=aEx.Orientation();
1794       //
1795       if (!i) {
1796         aOrC=TopAbs::Reverse(aOr);
1797         aE1=(*(TopoDS_Edge*)(&aEx));
1798         aF1=(*(TopoDS_Face*)(&aFx));
1799         aMFP.Add(aFx);
1800         continue;
1801       }
1802       //
1803       if (aOr==aOrC) {
1804         aLCEFx.Append(aCSx);
1805         aMFP.Add(aFx);
1806       }
1807     }
1808     //
1809     // F2
1810     BOPTools_AlgoTools::GetFaceOff(aE1, aF1, aLCEFx, aF2, theContext);
1811     //
1812     aCFF.SetShape1(aF1);
1813     aCFF.SetShape2(aF2);
1814     theLCFF.Append(aCFF);
1815     //
1816     aMFP.Add(aF1);
1817     aMFP.Add(aF2);
1818     //
1819     // refine aLCEF
1820     aLCEFx.Clear();
1821     aLCEFx=aLCEF;
1822     aLCEF.Clear();
1823     aIt.Initialize(aLCEFx);
1824     for (; aIt.More(); aIt.Next()) {
1825       const BOPTools_CoupleOfShape& aCSx=aIt.Value();
1826       const TopoDS_Shape& aFx=aCSx.Shape2();
1827       if (!aMFP.Contains(aFx)) {
1828         aLCEF.Append(aCSx);
1829       }
1830     }
1831     //
1832     aNbCEF=aLCEF.Extent();
1833   }//while(aNbCEF) {
1834   //
1835   return bFound;
1836 }
1837 //=======================================================================
1838 //function : AngleWithRef
1839 //purpose  :
1840 //=======================================================================
AngleWithRef(const gp_Dir & theD1,const gp_Dir & theD2,const gp_Dir & theDRef)1841 Standard_Real AngleWithRef(const gp_Dir& theD1,
1842                            const gp_Dir& theD2,
1843                            const gp_Dir& theDRef)
1844 {
1845   Standard_Real aCosinus, aSinus, aBeta, aHalfPI, aScPr;
1846   gp_XYZ aXYZ;
1847   //
1848   aHalfPI=0.5*M_PI;
1849   //
1850   const gp_XYZ& aXYZ1=theD1.XYZ();
1851   const gp_XYZ& aXYZ2=theD2.XYZ();
1852   aXYZ=aXYZ1.Crossed(aXYZ2);
1853   aSinus=aXYZ.Modulus();
1854   aCosinus=theD1*theD2;
1855   //
1856   aBeta=0.;
1857   if (aSinus>=0.) {
1858     aBeta=aHalfPI*(1.-aCosinus);
1859   }
1860   else {
1861     aBeta=2.*M_PI-aHalfPI*(3.+aCosinus);
1862   }
1863   //
1864   aScPr=aXYZ.Dot(theDRef.XYZ());
1865   if (aScPr<0.) {
1866     aBeta=-aBeta;
1867   }
1868   return aBeta;
1869 }
1870 //=======================================================================
1871 // function: IsBlockInOnFace
1872 // purpose:
1873 //=======================================================================
IsBlockInOnFace(const IntTools_Range & aShrR,const TopoDS_Face & aF,const TopoDS_Edge & aE1,const Handle (IntTools_Context)& aContext)1874 Standard_Boolean BOPTools_AlgoTools::IsBlockInOnFace
1875   (const IntTools_Range& aShrR,
1876    const TopoDS_Face& aF,
1877    const TopoDS_Edge& aE1,
1878    const Handle(IntTools_Context)& aContext)
1879 {
1880   Standard_Boolean bFlag;
1881   Standard_Real f1, l1, ULD, VLD;
1882   gp_Pnt2d aP2D;
1883   gp_Pnt aP11, aP12;
1884   //
1885   aShrR.Range(f1, l1);
1886   Standard_Real dt=0.0075,  k;//dt=0.001,  k;
1887   k=dt*(l1-f1);
1888   f1=f1+k;
1889   l1=l1-k;
1890   //
1891   // Treatment P11
1892   BOPTools_AlgoTools::PointOnEdge(aE1, f1, aP11);
1893   //
1894   GeomAPI_ProjectPointOnSurf& aProjector=aContext->ProjPS(aF);
1895   aProjector.Perform(aP11);
1896   //
1897   bFlag=aProjector.IsDone();
1898   if (!bFlag) {
1899     return bFlag;
1900   }
1901 
1902   aProjector.LowerDistanceParameters(ULD, VLD);
1903   aP2D.SetCoord(ULD, VLD);
1904   //
1905   bFlag=aContext->IsPointInOnFace (aF, aP2D);
1906   //
1907   if (!bFlag) {
1908     return bFlag;
1909   }
1910   //
1911   // Treatment P12
1912   BOPTools_AlgoTools::PointOnEdge(aE1, l1, aP12);
1913   //
1914   aProjector.Perform(aP12);
1915   //
1916   bFlag=aProjector.IsDone();
1917   if (!bFlag) {
1918     return bFlag;
1919   }
1920 
1921   aProjector.LowerDistanceParameters(ULD, VLD);
1922   aP2D.SetCoord(ULD, VLD);
1923   //
1924   bFlag=aContext->IsPointInOnFace (aF, aP2D);
1925   //
1926   if (!bFlag) {
1927     return bFlag;
1928   }
1929   //
1930   // Treatment intemediate
1931   Standard_Real m1, aTolF, aTolE, aTol, aDist;
1932   m1=IntTools_Tools::IntermediatePoint(f1, l1);
1933   BOPTools_AlgoTools::PointOnEdge(aE1, m1, aP12);
1934   //
1935   aProjector.Perform(aP12);
1936   //
1937   bFlag=aProjector.IsDone();
1938   if (!bFlag) {
1939     return bFlag;
1940   }
1941   //
1942   aTolE=BRep_Tool::Tolerance(aE1);
1943   aTolF=BRep_Tool::Tolerance(aF);
1944   aTol=aTolE+aTolF;
1945   aDist=aProjector.LowerDistance();
1946   if (aDist > aTol){
1947    return Standard_False;
1948   }
1949 
1950   aProjector.LowerDistanceParameters(ULD, VLD);
1951   aP2D.SetCoord(ULD, VLD);
1952   //
1953   bFlag=aContext->IsPointInOnFace (aF, aP2D);
1954   //
1955   if (!bFlag) {
1956     return bFlag;
1957   }
1958   return bFlag;
1959 }
1960 
1961 //=======================================================================
1962 //function : IsMicroEdge
1963 //purpose  :
1964 //=======================================================================
IsMicroEdge(const TopoDS_Edge & aE,const Handle (IntTools_Context)& aCtx,const Standard_Boolean bCheckSplittable)1965 Standard_Boolean BOPTools_AlgoTools::IsMicroEdge
1966   (const TopoDS_Edge& aE,
1967    const Handle(IntTools_Context)& aCtx,
1968    const Standard_Boolean bCheckSplittable)
1969 {
1970   Standard_Boolean bRet;
1971   Standard_Real aT1, aT2, aTmp;
1972   Handle(Geom_Curve) aC3D;
1973   TopoDS_Vertex aV1, aV2;
1974   //
1975   bRet=(BRep_Tool::Degenerated(aE) ||
1976         !BRep_Tool::IsGeometric(aE));
1977   if (bRet) {
1978     return bRet;
1979   }
1980   //
1981   aC3D=BRep_Tool::Curve(aE, aT1, aT2);
1982   TopExp::Vertices(aE, aV1, aV2);
1983   aT1=BRep_Tool::Parameter(aV1, aE);
1984   aT2=BRep_Tool::Parameter(aV2, aE);
1985   if (aT2<aT1) {
1986     aTmp=aT1;
1987     aT1=aT2;
1988     aT2=aTmp;
1989   }
1990   //
1991   IntTools_ShrunkRange aSR;
1992   aSR.SetContext(aCtx);
1993   aSR.SetData(aE, aT1, aT2, aV1, aV2);
1994   aSR.Perform();
1995   bRet = !aSR.IsDone();
1996   if (!bRet && bCheckSplittable) {
1997     bRet = !aSR.IsSplittable();
1998   }
1999   //
2000   return bRet;
2001 }
2002 
2003 //=======================================================================
2004 //function : GetFaceDir
2005 //purpose  : Get binormal direction for the face in the point aP
2006 //=======================================================================
GetFaceDir(const TopoDS_Edge & aE,const TopoDS_Face & aF,const gp_Pnt & aP,const Standard_Real aT,const gp_Dir & aDTgt,const Standard_Boolean theSmallFaces,gp_Dir & aDN,gp_Dir & aDB,const Handle (IntTools_Context)& theContext,GeomAPI_ProjectPointOnSurf & aProjPL,const Standard_Real aDt)2007 Standard_Boolean GetFaceDir(const TopoDS_Edge& aE,
2008                             const TopoDS_Face& aF,
2009                             const gp_Pnt& aP,
2010                             const Standard_Real aT,
2011                             const gp_Dir& aDTgt,
2012                             const Standard_Boolean theSmallFaces,
2013                             gp_Dir& aDN,
2014                             gp_Dir& aDB,
2015                             const Handle(IntTools_Context)& theContext,
2016                             GeomAPI_ProjectPointOnSurf& aProjPL,
2017                             const Standard_Real aDt)
2018 {
2019   Standard_Real aTolE;
2020   gp_Pnt aPx;
2021   //
2022   BOPTools_AlgoTools3D::GetNormalToFaceOnEdge(aE, aF, aT, aDN, theContext);
2023   if (aF.Orientation()==TopAbs_REVERSED){
2024     aDN.Reverse();
2025   }
2026   //
2027   aTolE=BRep_Tool::Tolerance(aE);
2028   aDB = aDN^aDTgt;
2029   //
2030   // do not try to look for the point in the small face by intersecting
2031   // it with the circle because, most likely, the intersection point will
2032   // be out of the face
2033   Standard_Boolean bFound = !theSmallFaces &&
2034     FindPointInFace(aF, aP, aDB, aPx, theContext, aProjPL, aDt, aTolE);
2035   if (!bFound) {
2036     // if the first method did not succeed, try to use hatcher to find the point
2037     bFound = BOPTools_AlgoTools3D::GetApproxNormalToFaceOnEdge
2038       (aE, aF, aT, aDt, aPx, aDN, theContext);
2039     aProjPL.Perform(aPx);
2040     Standard_ASSERT_RETURN(aProjPL.IsDone(),
2041       "GetFaceDir: Project point on plane is failed", Standard_False);
2042     aPx = aProjPL.NearestPoint();
2043     gp_Vec aVec(aP, aPx);
2044     aDB.SetXYZ(aVec.XYZ());
2045   }
2046   //
2047   return bFound;
2048 }
2049 //=======================================================================
2050 //function : FindPointInFace
2051 //purpose  : Find a point in the face in direction of <aDB>.
2052 //           To get this point the method intersects the circle with radius
2053 //           <aDt> built in point <aP> with normal perpendicular to <aDB>.
2054 //=======================================================================
FindPointInFace(const TopoDS_Face & aF,const gp_Pnt & aP,gp_Dir & aDB,gp_Pnt & aPOut,const Handle (IntTools_Context)& theContext,GeomAPI_ProjectPointOnSurf & aProjPL,const Standard_Real aDt,const Standard_Real aTolE)2055 Standard_Boolean FindPointInFace(const TopoDS_Face& aF,
2056                                  const gp_Pnt& aP,
2057                                  gp_Dir& aDB,
2058                                  gp_Pnt& aPOut,
2059                                  const Handle(IntTools_Context)& theContext,
2060                                  GeomAPI_ProjectPointOnSurf& aProjPL,
2061                                  const Standard_Real aDt,
2062                                  const Standard_Real aTolE)
2063 {
2064   Standard_Integer aNbItMax;
2065   Standard_Real aDist, aDTol, aPM, anEps;
2066   Standard_Boolean bRet;
2067   gp_Pnt aP1, aPS;
2068   //
2069   aDTol = Precision::Angular();
2070   aPM = aP.XYZ().Modulus();
2071   if (aPM > 1000.) {
2072     aDTol = 5.e-16 * aPM;
2073   }
2074   bRet = Standard_False;
2075   aNbItMax = 15;
2076   anEps = Precision::SquareConfusion();
2077   //
2078   GeomAPI_ProjectPointOnSurf& aProj=theContext->ProjPS(aF);
2079   //
2080   aPS=aP;
2081   aProj.Perform(aPS);
2082   if (!aProj.IsDone()) {
2083     return bRet;
2084   }
2085   aPS=aProj.NearestPoint();
2086   aProjPL.Perform(aPS);
2087   aPS=aProjPL.NearestPoint();
2088   //
2089   aPS.SetXYZ(aPS.XYZ()+2.*aTolE*aDB.XYZ());
2090   aProj.Perform(aPS);
2091   if (!aProj.IsDone()) {
2092     return bRet;
2093   }
2094   aPS=aProj.NearestPoint();
2095   aProjPL.Perform(aPS);
2096   aPS=aProjPL.NearestPoint();
2097   //
2098   do {
2099     aP1.SetXYZ(aPS.XYZ()+aDt*aDB.XYZ());
2100     //
2101     aProj.Perform(aP1);
2102     if (!aProj.IsDone()) {
2103       return bRet;
2104     }
2105     aPOut = aProj.NearestPoint();
2106     aDist = aProj.LowerDistance();
2107     //
2108     aProjPL.Perform(aPOut);
2109     aPOut = aProjPL.NearestPoint();
2110     //
2111     gp_Vec aV(aPS, aPOut);
2112     if (aV.SquareMagnitude() < anEps) {
2113       return bRet;
2114     }
2115     aDB.SetXYZ(aV.XYZ());
2116   } while (aDist > aDTol && --aNbItMax);
2117   //
2118   bRet = aDist < aDTol;
2119   return bRet;
2120 }
2121 //=======================================================================
2122 //function : MinStep3D
2123 //purpose  :
2124 //=======================================================================
MinStep3D(const TopoDS_Edge & theE1,const TopoDS_Face & theF1,const BOPTools_ListOfCoupleOfShape & theLCS,const gp_Pnt & aP,const Handle (IntTools_Context)& theContext,Standard_Boolean & theSmallFaces)2125 Standard_Real MinStep3D(const TopoDS_Edge& theE1,
2126                         const TopoDS_Face& theF1,
2127                         const BOPTools_ListOfCoupleOfShape& theLCS,
2128                         const gp_Pnt& aP,
2129                         const Handle(IntTools_Context)& theContext,
2130                         Standard_Boolean& theSmallFaces)
2131 {
2132   Standard_Real aDt, aTolE, aTolF, aDtMax, aDtMin;
2133   //
2134   // add the current pair of edge/face for checking as well
2135   BOPTools_CoupleOfShape aCS1;
2136   aCS1.SetShape1(theE1);
2137   aCS1.SetShape2(theF1);
2138   //
2139   BOPTools_ListOfCoupleOfShape aLCS = theLCS;
2140   aLCS.Append(aCS1);
2141   //
2142   aTolE = BRep_Tool::Tolerance(theE1);
2143   aDtMax = -1.;
2144   aDtMin = 5.e-6;
2145   //
2146   BOPTools_ListIteratorOfListOfCoupleOfShape aIt(aLCS);
2147   for (; aIt.More(); aIt.Next()) {
2148     const BOPTools_CoupleOfShape& aCS = aIt.Value();
2149     const TopoDS_Face& aF = (*(TopoDS_Face*)(&aCS.Shape2()));
2150     //
2151     aTolF = BRep_Tool::Tolerance(aF);
2152     aDt = 2*(aTolE + aTolF);
2153     if (aDt > aDtMax) {
2154       aDtMax = aDt;
2155     }
2156     //
2157     // try to compute the minimal 3D step
2158     const BRepAdaptor_Surface& aBAS = theContext->SurfaceAdaptor(aF);
2159     Standard_Real aR = 0.;
2160     GeomAbs_SurfaceType aSType = aBAS.GetType();
2161     switch (aSType) {
2162     case GeomAbs_Cylinder: {
2163       aR = aBAS.Cylinder().Radius();
2164       break;
2165     }
2166     case GeomAbs_Cone: {
2167       gp_Lin aL(aBAS.Cone().Axis());
2168       aR = aL.Distance(aP);
2169       break;
2170     }
2171     case GeomAbs_Sphere: {
2172       aDtMin = Max(aDtMin, 5.e-4);
2173       aR = aBAS.Sphere().Radius();
2174       break;
2175     }
2176     case GeomAbs_Torus: {
2177       aR = aBAS.Torus().MajorRadius();
2178       break;
2179     }
2180     default:
2181       aDtMin = Max(aDtMin, 5.e-4);
2182       break;
2183     }
2184     //
2185     if (aR > 100.) {
2186       Standard_Real d = 10*Precision::PConfusion();
2187       aDtMin = Max(aDtMin, sqrt(d*d + 2*d*aR));
2188     }
2189   }
2190   //
2191   if (aDtMax < aDtMin) {
2192     aDtMax = aDtMin;
2193   }
2194   //
2195   // check if the computed 3D step is too big for any of the faces in the list
2196   aIt.Initialize(aLCS);
2197   for (; aIt.More(); aIt.Next()) {
2198     const BOPTools_CoupleOfShape& aCS = aIt.Value();
2199     const TopoDS_Face& aF = (*(TopoDS_Face*)(&aCS.Shape2()));
2200     //
2201     const BRepAdaptor_Surface& aBAS = theContext->SurfaceAdaptor(aF);
2202     //
2203     Standard_Real aUMin, aUMax, aVMin, aVMax;
2204     theContext->UVBounds(aF, aUMin, aUMax, aVMin, aVMax);
2205     //
2206     Standard_Real aDU = aUMax - aUMin;
2207     if (aDU > 0.) {
2208       Standard_Real aURes = aBAS.UResolution(aDtMax);
2209       if (2*aURes > aDU) {
2210         break;
2211       }
2212     }
2213     //
2214     Standard_Real aDV = aVMax - aVMin;
2215     if (aDV > 0.) {
2216       Standard_Real aVRes = aBAS.VResolution(aDtMax);
2217       if (2*aVRes > aDV) {
2218         break;
2219       }
2220     }
2221   }
2222   //
2223   theSmallFaces = aIt.More();
2224   //
2225   return aDtMax;
2226 }
2227 //=======================================================================
2228 //function : IsOpenShell
2229 //purpose  :
2230 //=======================================================================
IsOpenShell(const TopoDS_Shell & aSh)2231 Standard_Boolean BOPTools_AlgoTools::IsOpenShell(const TopoDS_Shell& aSh)
2232 {
2233   Standard_Boolean bRet;
2234   Standard_Integer i, aNbE, aNbF;
2235   TopAbs_Orientation aOrF;
2236   TopTools_IndexedDataMapOfShapeListOfShape aMEF;
2237   TopTools_ListIteratorOfListOfShape aItLS;
2238   //
2239   bRet=Standard_False;
2240   //
2241   TopExp::MapShapesAndAncestors(aSh, TopAbs_EDGE, TopAbs_FACE, aMEF);
2242   //
2243   aNbE=aMEF.Extent();
2244   for (i=1; i<=aNbE; ++i) {
2245     const TopoDS_Edge& aE=*((TopoDS_Edge*)&aMEF.FindKey(i));
2246     if (BRep_Tool::Degenerated(aE)) {
2247       continue;
2248     }
2249     //
2250     aNbF=0;
2251     const TopTools_ListOfShape& aLF=aMEF(i);
2252     aItLS.Initialize(aLF);
2253     for (; aItLS.More(); aItLS.Next()) {
2254       const TopoDS_Shape& aF=aItLS.Value();
2255       aOrF=aF.Orientation();
2256       if (aOrF==TopAbs_INTERNAL || aOrF==TopAbs_EXTERNAL) {
2257         continue;
2258       }
2259       ++aNbF;
2260     }
2261     //
2262     if (aNbF==1) {
2263       bRet=!bRet; // True
2264       break;
2265     }
2266   }
2267   //
2268   return bRet;
2269 }
2270 //=======================================================================
2271 //function : IsInvertedSolid
2272 //purpose  :
2273 //=======================================================================
IsInvertedSolid(const TopoDS_Solid & aSolid)2274 Standard_Boolean BOPTools_AlgoTools::IsInvertedSolid
2275   (const TopoDS_Solid& aSolid)
2276 {
2277   Standard_Real aTolS;
2278   TopAbs_State aState;
2279   BRepClass3d_SolidClassifier aSC(aSolid);
2280   //
2281   aTolS=1.e-7;
2282   aSC.PerformInfinitePoint(aTolS);
2283   aState=aSC.State();
2284   return (aState==TopAbs_IN);
2285 }
2286