1eeb367979eb931b7829902c9d7a4d3847b15f05
[occt.git] / src / BRepOffset / BRepOffset_Analyse.cxx
1 // Created on: 1995-10-20
2 // Created by: Yves FRICAUD
3 // Copyright (c) 1995-1999 Matra Datavision
4 // Copyright (c) 1999-2014 OPEN CASCADE SAS
5 //
6 // This file is part of Open CASCADE Technology software library.
7 //
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.
13 //
14 // Alternatively, this file may be used under the terms of Open CASCADE
15 // commercial license or contractual agreement.
16
17
18 #include <Adaptor3d_Surface.hxx>
19 #include <BOPTools_AlgoTools.hxx>
20 #include <BOPTools_AlgoTools3D.hxx>
21 #include <BRep_Builder.hxx>
22 #include <BRep_Tool.hxx>
23 #include <BRepAdaptor_Curve.hxx>
24 #include <BRepAdaptor_Surface.hxx>
25 #include <BRepOffset_Analyse.hxx>
26 #include <BRepOffset_Interval.hxx>
27 #include <BRepOffset_ListIteratorOfListOfInterval.hxx>
28 #include <BRepOffset_Tool.hxx>
29 #include <BRepPrimAPI_MakePrism.hxx>
30 #include <BRepTools.hxx>
31 #include <Geom2d_Curve.hxx>
32 #include <Geom_Curve.hxx>
33 #include <Geom_Surface.hxx>
34 #include <gp.hxx>
35 #include <gp_Dir.hxx>
36 #include <gp_Pnt.hxx>
37 #include <gp_Pnt2d.hxx>
38 #include <gp_Vec.hxx>
39 #include <IntTools_Context.hxx>
40 #include <Precision.hxx>
41 #include <TopExp.hxx>
42 #include <TopExp_Explorer.hxx>
43 #include <TopoDS.hxx>
44 #include <TopoDS_Compound.hxx>
45 #include <TopoDS_Edge.hxx>
46 #include <TopoDS_Face.hxx>
47 #include <TopoDS_Shape.hxx>
48 #include <TopoDS_Vertex.hxx>
49 #include <TopTools_ListIteratorOfListOfShape.hxx>
50 #include <TopTools_MapOfShape.hxx>
51 #include <ChFi3d.hxx>
52
53 static void CorrectOrientationOfTangent(gp_Vec& TangVec,
54                                         const TopoDS_Vertex& aVertex,
55                                         const TopoDS_Edge& anEdge)
56 {
57   TopoDS_Vertex Vlast = TopExp::LastVertex(anEdge);
58   if (aVertex.IsSame(Vlast))
59     TangVec.Reverse();
60 }
61 //=======================================================================
62 //function : BRepOffset_Analyse
63 //purpose  : 
64 //=======================================================================
65
66 BRepOffset_Analyse::BRepOffset_Analyse()
67 : myOffset (0.0), myDone (Standard_False)
68 {
69 }
70
71 //=======================================================================
72 //function : BRepOffset_Analyse
73 //purpose  : 
74 //=======================================================================
75 BRepOffset_Analyse::BRepOffset_Analyse(const TopoDS_Shape& S, 
76                                        const Standard_Real Angle)
77 : myOffset (0.0), myDone (Standard_False)
78 {
79   Perform( S, Angle);
80 }
81
82 //=======================================================================
83 //function : EdgeAnlyse
84 //purpose  : 
85 //=======================================================================
86 static void EdgeAnalyse(const TopoDS_Edge&         E,
87                                           const TopoDS_Face&         F1,
88                                           const TopoDS_Face&         F2,
89                                           const Standard_Real        SinTol,
90                                                 BRepOffset_ListOfInterval& LI)
91 {
92   
93   Standard_Real   f,l;
94   BRep_Tool::Range(E, F1, f, l);
95   BRepOffset_Interval I;
96   I.First(f); I.Last(l);
97   //
98   // Tangent if the regularity is at least G1.
99   if (BRep_Tool::HasContinuity(E,F1,F2)) {
100     if (BRep_Tool::Continuity(E,F1,F2) > GeomAbs_C0) {
101       I.Type(ChFiDS_Tangential);
102       LI.Append(I);
103       return;
104     }
105   }
106   //
107   ChFiDS_TypeOfConcavity aType = ChFi3d::DefineConnectType(E, F1, F2,
108                                                            SinTol, Standard_False);
109   if(aType != ChFiDS_Tangential)
110   {
111     aType = ChFi3d::DefineConnectType(E, F1, F2, SinTol, Standard_True);
112   }
113   I.Type(aType);
114   LI.Append(I);
115 }
116
117 //=======================================================================
118 //function : BuildAncestors
119 //purpose  : 
120 //=======================================================================
121 static void BuildAncestors (const TopoDS_Shape&                        S,
122                             TopTools_IndexedDataMapOfShapeListOfShape& MA)
123 {  
124   MA.Clear();
125   TopExp::MapShapesAndUniqueAncestors(S,TopAbs_VERTEX,TopAbs_EDGE,MA);
126   TopExp::MapShapesAndUniqueAncestors(S,TopAbs_EDGE  ,TopAbs_FACE,MA);
127 }
128
129 //=======================================================================
130 //function : Perform
131 //purpose  : 
132 //=======================================================================
133 void BRepOffset_Analyse::Perform (const TopoDS_Shape& S, 
134                                   const Standard_Real Angle)
135 {
136   myShape = S;
137   myNewFaces .Clear();
138   myGenerated.Clear();
139   myReplacement.Clear();
140   myDescendants.Clear();
141
142   myAngle                = Angle;
143   Standard_Real SinTol = Abs (Sin(Angle));
144
145   // Build ancestors.
146   BuildAncestors (S,myAncestors);
147
148   TopTools_ListOfShape aLETang;
149
150   TopExp_Explorer Exp(S.Oriented(TopAbs_FORWARD),TopAbs_EDGE);
151   for ( ; Exp.More(); Exp.Next()) {
152     const TopoDS_Edge& E = TopoDS::Edge(Exp.Current());
153     if (!myMapEdgeType.IsBound(E)) {
154       BRepOffset_ListOfInterval LI;
155       myMapEdgeType.Bind(E,LI);
156       
157       const TopTools_ListOfShape& L = Ancestors(E);
158       if ( L.IsEmpty()) 
159         continue;
160
161       if (L.Extent() == 2) {
162         const TopoDS_Face& F1 = TopoDS::Face (L.First());
163         const TopoDS_Face& F2 = TopoDS::Face (L.Last());
164         EdgeAnalyse (E, F1, F2, SinTol, myMapEdgeType (E));
165
166         // For tangent faces add artificial perpendicular face
167         // to close the gap between them (if they have different offset values)
168         if (myMapEdgeType(E).Last().Type() == ChFiDS_Tangential)
169           aLETang.Append (E);
170       }
171       else if (L.Extent() == 1) {
172         Standard_Real U1, U2;
173         const TopoDS_Face& F = TopoDS::Face (L.First());
174         BRep_Tool::Range (E, F, U1, U2);
175         BRepOffset_Interval Inter (U1, U2, ChFiDS_Other);
176
177         if (!BRepTools::IsReallyClosed (E, F)) {
178           Inter.Type (ChFiDS_FreeBound);
179         }
180         myMapEdgeType (E).Append (Inter);
181       }
182       else {  
183 #ifdef OCCT_DEBUG
184         std::cout <<"edge shared by more than two faces"<<std::endl;
185 #endif  
186       }
187     }
188   }
189
190   TreatTangentFaces (aLETang);
191   myDone = Standard_True;
192 }
193
194 //=======================================================================
195 //function : Generated
196 //purpose  : 
197 //=======================================================================
198 void BRepOffset_Analyse::TreatTangentFaces (const TopTools_ListOfShape& theLE)
199 {
200   if (theLE.IsEmpty() || myFaceOffsetMap.IsEmpty())
201   {
202     // Noting to do: either there are no tangent faces in the shape or
203     //               the face offset map has not been provided
204     return;
205   }
206
207   // Select the edges which connect faces with different offset values
208   TopoDS_Compound aCETangent;
209   BRep_Builder().MakeCompound (aCETangent);
210   // Bind to each tangent edge a max offset value of its faces
211   TopTools_DataMapOfShapeReal anEdgeOffsetMap;
212   // Bind vertices of the tangent edges with connected edges
213   // of the face with smaller offset value
214   TopTools_DataMapOfShapeShape aDMVEMin;
215   for (TopTools_ListOfShape::Iterator it (theLE); it.More(); it.Next())
216   {
217     const TopoDS_Shape& aE = it.Value();
218     const TopTools_ListOfShape& aLA = Ancestors (aE);
219
220     const TopoDS_Shape& aF1 = aLA.First(), aF2 = aLA.Last();
221
222     const Standard_Real *pOffsetVal1 = myFaceOffsetMap.Seek (aF1);
223     const Standard_Real *pOffsetVal2 = myFaceOffsetMap.Seek (aF2);
224     const Standard_Real anOffsetVal1 = pOffsetVal1 ? Abs (*pOffsetVal1) : myOffset;
225     const Standard_Real anOffsetVal2 = pOffsetVal2 ? Abs (*pOffsetVal2) : myOffset;
226     if (anOffsetVal1 != anOffsetVal2)
227     {
228       BRep_Builder().Add (aCETangent, aE);
229       anEdgeOffsetMap.Bind (aE, Max (anOffsetVal1, anOffsetVal2));
230
231       const TopoDS_Shape& aFMin = anOffsetVal1 < anOffsetVal2 ? aF1 : aF2;
232       for (TopoDS_Iterator itV (aE); itV.More(); itV.Next())
233       {
234         const TopoDS_Shape& aV = itV.Value();
235         if (Ancestors (aV).Extent() == 3)
236         {
237           for (TopExp_Explorer expE (aFMin, TopAbs_EDGE); expE.More(); expE.Next())
238           {
239             const TopoDS_Shape& aEMin = expE.Current();
240             if (aEMin.IsSame (aE))
241               continue;
242             for (TopoDS_Iterator itV1 (aEMin); itV1.More(); itV1.Next())
243             {
244               const TopoDS_Shape& aVx = itV1.Value();
245               if (aV.IsSame (aVx))
246                 aDMVEMin.Bind (aV, aEMin);
247             }
248           }
249         }
250       }
251     }
252   }
253
254   if (anEdgeOffsetMap.IsEmpty())
255     return;
256
257   // Create map of Face ancestors for the vertices on tangent edges
258   TopTools_DataMapOfShapeListOfShape aDMVFAnc;
259
260   for (TopTools_ListOfShape::Iterator itE (theLE); itE.More(); itE.Next())
261   {
262     const TopoDS_Shape& aE = itE.Value();
263     if (!anEdgeOffsetMap.IsBound (aE))
264       continue;
265
266     TopTools_MapOfShape aMFence;
267     {
268       const TopTools_ListOfShape& aLEA = Ancestors (aE);
269       for (TopTools_ListOfShape::Iterator itLEA (aLEA); itLEA.More(); itLEA.Next())
270         aMFence.Add (itLEA.Value());
271     }
272
273     for (TopoDS_Iterator itV (aE); itV.More(); itV.Next())
274     {
275       const TopoDS_Shape& aV = itV.Value();
276       TopTools_ListOfShape* pLFA = aDMVFAnc.Bound (aV, TopTools_ListOfShape());
277       const TopTools_ListOfShape& aLVA = Ancestors (aV);
278       for (TopTools_ListOfShape::Iterator itLVA (aLVA); itLVA.More(); itLVA.Next())
279       {
280         const TopoDS_Edge& aEA = TopoDS::Edge (itLVA.Value());
281         const BRepOffset_ListOfInterval* pIntervals = myMapEdgeType.Seek (aEA);
282         if (!pIntervals || pIntervals->IsEmpty())
283           continue;
284         if (pIntervals->First().Type() == ChFiDS_Tangential)
285           continue;
286
287         const TopTools_ListOfShape& aLEA = Ancestors (aEA);
288         for (TopTools_ListOfShape::Iterator itLEA (aLEA); itLEA.More(); itLEA.Next())
289         {
290           const TopoDS_Shape& aFA = itLEA.Value();
291           if (aMFence.Add (aFA))
292             pLFA->Append (aFA);
293         }
294       }
295     }
296   }
297
298   Handle(IntTools_Context) aCtx = new IntTools_Context();
299   // Tangency criteria
300   Standard_Real aSinTol = Abs (Sin (myAngle));
301
302   // Make blocks of connected edges
303   TopTools_ListOfListOfShape aLCB;
304   TopTools_IndexedDataMapOfShapeListOfShape aMVEMap;
305
306   BOPTools_AlgoTools::MakeConnexityBlocks (aCETangent, TopAbs_VERTEX, TopAbs_EDGE, aLCB, aMVEMap);
307
308   // Analyze each block to find co-planar edges
309   for (TopTools_ListOfListOfShape::Iterator itLCB (aLCB); itLCB.More(); itLCB.Next())
310   {
311     const TopTools_ListOfShape& aCB = itLCB.Value();
312
313     TopTools_MapOfShape aMFence;
314     for (TopTools_ListOfShape::Iterator itCB1 (aCB); itCB1.More(); itCB1.Next())
315     {
316       const TopoDS_Edge& aE1 = TopoDS::Edge (itCB1.Value());
317       if (!aMFence.Add (aE1))
318         continue;
319
320       TopoDS_Compound aBlock;
321       BRep_Builder().MakeCompound (aBlock);
322       BRep_Builder().Add (aBlock, aE1.Oriented (TopAbs_FORWARD));
323
324       Standard_Real anOffset = anEdgeOffsetMap.Find (aE1);
325       const TopTools_ListOfShape& aLF1 = Ancestors (aE1);
326
327       gp_Dir aDN1;
328       BOPTools_AlgoTools3D::GetNormalToFaceOnEdge (aE1, TopoDS::Face (aLF1.First()), aDN1);
329
330       TopTools_ListOfShape::Iterator itCB2 = itCB1;
331       for (itCB2.Next(); itCB2.More(); itCB2.Next())
332       {
333         const TopoDS_Edge& aE2 = TopoDS::Edge (itCB2.Value());
334         if (aMFence.Contains (aE2))
335           continue;
336
337         const TopTools_ListOfShape& aLF2 = Ancestors (aE2);
338
339         gp_Dir aDN2;
340         BOPTools_AlgoTools3D::GetNormalToFaceOnEdge (aE2, TopoDS::Face (aLF2.First()), aDN2);
341
342         if (aDN1.XYZ().Crossed (aDN2.XYZ()).Modulus() < aSinTol)
343         {
344           BRep_Builder().Add (aBlock, aE2.Oriented (TopAbs_FORWARD));
345           aMFence.Add (aE2);
346           anOffset = Max (anOffset, anEdgeOffsetMap.Find (aE2));
347         }
348       }
349
350       // Make the prism
351       BRepPrimAPI_MakePrism aMP (aBlock, gp_Vec (aDN1.XYZ()) * anOffset);
352       if (!aMP.IsDone())
353         continue;
354
355       TopTools_IndexedDataMapOfShapeListOfShape aPrismAncestors;
356       TopExp::MapShapesAndAncestors (aMP.Shape(), TopAbs_EDGE, TopAbs_FACE, aPrismAncestors);
357       TopExp::MapShapesAndAncestors (aMP.Shape(), TopAbs_VERTEX, TopAbs_EDGE, aPrismAncestors);
358
359       for (TopoDS_Iterator itE (aBlock); itE.More(); itE.Next())
360       {
361         const TopoDS_Edge& aE = TopoDS::Edge (itE.Value());
362         const TopTools_ListOfShape& aLG = aMP.Generated (aE);
363         TopoDS_Face aFNew = TopoDS::Face (aLG.First());
364
365         TopTools_ListOfShape& aLA = myAncestors.ChangeFromKey (aE);
366
367         TopoDS_Shape aF1 = aLA.First();
368         TopoDS_Shape aF2 = aLA.Last();
369
370         const Standard_Real *pOffsetVal1 = myFaceOffsetMap.Seek (aF1);
371         const Standard_Real *pOffsetVal2 = myFaceOffsetMap.Seek (aF2);
372         const Standard_Real anOffsetVal1 = pOffsetVal1 ? Abs (*pOffsetVal1) : myOffset;
373         const Standard_Real anOffsetVal2 = pOffsetVal2 ? Abs (*pOffsetVal2) : myOffset;
374
375         const TopoDS_Shape& aFToRemove = anOffsetVal1 > anOffsetVal2 ? aF1 : aF2;
376         const TopoDS_Shape& aFOpposite = anOffsetVal1 > anOffsetVal2 ? aF2 : aF1;
377
378         // Orient the face so its normal is directed to smaller offset face
379         {
380           // get normal of the new face
381           gp_Dir aDN;
382           BOPTools_AlgoTools3D::GetNormalToFaceOnEdge (aE, aFNew, aDN);
383         
384           // get bi-normal for the aFOpposite
385           TopoDS_Edge aEInF;
386           for (TopExp_Explorer aExpE (aFOpposite, TopAbs_EDGE); aExpE.More(); aExpE.Next())
387           {
388             if (aE.IsSame (aExpE.Current()))
389             {
390               aEInF = TopoDS::Edge (aExpE.Current());
391               break;
392             }
393           }
394         
395           gp_Pnt2d aP2d;
396           gp_Pnt aPInF;
397           Standard_Real f, l;
398           const Handle(Geom_Curve)& aC3D = BRep_Tool::Curve (aEInF, f, l);
399           gp_Pnt aPOnE = aC3D->Value ((f + l) / 2.);
400           BOPTools_AlgoTools3D::PointNearEdge (aEInF, TopoDS::Face (aFOpposite), (f + l) / 2., 1.e-5, aP2d, aPInF);
401         
402           gp_Vec aBN (aPOnE, aPInF);
403         
404           if (aBN.Dot (aDN) < 0)
405             aFNew.Reverse();
406         }
407
408         // Remove the face with bigger offset value from edge ancestors
409         for (TopTools_ListOfShape::Iterator itA (aLA); itA.More();itA.Next())
410         {
411           if (itA.Value().IsSame (aFToRemove))
412           {
413             aLA.Remove (itA);
414             break;
415           }
416         }
417         aLA.Append (aFNew);
418
419         myMapEdgeType (aE).Clear();
420         // Analyze edge again
421         EdgeAnalyse (aE, TopoDS::Face (aFOpposite), aFNew,  aSinTol, myMapEdgeType (aE));
422
423         // Analyze vertices
424         TopTools_MapOfShape aFNewEdgeMap;
425         aFNewEdgeMap.Add (aE);
426         for (TopoDS_Iterator itV (aE); itV.More(); itV.Next())
427         {
428           const TopoDS_Shape& aV = itV.Value();
429           // Add Side edge to map of Ancestors with the correct orientation
430           TopoDS_Edge aEG = TopoDS::Edge (aMP.Generated (aV).First());
431           myGenerated.Bind (aV, aEG);
432           {
433             for (TopExp_Explorer anExpEg (aFNew, TopAbs_EDGE); anExpEg.More(); anExpEg.Next())
434             {
435               if (anExpEg.Current().IsSame (aEG))
436               {
437                 aEG = TopoDS::Edge (anExpEg.Current());
438                 break;
439               }
440             }
441           }
442
443           if (aDMVEMin.IsBound (aV))
444           {
445             const TopTools_ListOfShape* pSA = aDMVFAnc.Seek (aV);
446             if (pSA && pSA->Extent() == 1)
447             {
448               // Adjust orientation of generated edge to its new ancestor
449               TopoDS_Edge aEMin = TopoDS::Edge (aDMVEMin.Find (aV));
450               for (TopExp_Explorer expEx (pSA->First(), TopAbs_EDGE); expEx.More(); expEx.Next())
451               {
452                 if (expEx.Current().IsSame (aEMin))
453                 {
454                   aEMin = TopoDS::Edge (expEx.Current());
455                   break;
456                 }
457               }
458
459               TopAbs_Orientation anOriInEMin (TopAbs_FORWARD), anOriInEG (TopAbs_FORWARD);
460               
461               for (TopoDS_Iterator itx (aEMin); itx.More(); itx.Next())
462               {
463                 if (itx.Value().IsSame (aV))
464                 {
465                   anOriInEMin = itx.Value().Orientation();
466                   break;
467                 }
468               }
469               
470               for (TopoDS_Iterator itx (aEG); itx.More(); itx.Next())
471               {
472                 if (itx.Value().IsSame (aV))
473                 {
474                   anOriInEG = itx.Value().Orientation();
475                   break;
476                 }
477               }
478               
479               if (anOriInEG == anOriInEMin)
480                 aEG.Reverse();
481             }
482           }
483
484           TopTools_ListOfShape& aLVA = myAncestors.ChangeFromKey (aV);
485           if (!aLVA.Contains (aEG))
486             aLVA.Append (aEG);
487           aFNewEdgeMap.Add (aEG);
488
489           TopTools_ListOfShape& aLEGA =
490             myAncestors (myAncestors.Add (aEG, aPrismAncestors.FindFromKey (aEG)));
491           {
492             // Add ancestors from the shape
493             const TopTools_ListOfShape* pSA = aDMVFAnc.Seek (aV);
494             if (pSA && !pSA->IsEmpty())
495             {
496               TopTools_ListOfShape aLSA = *pSA;
497               aLEGA.Append (aLSA);
498             }
499           }
500
501           myMapEdgeType.Bind (aEG, BRepOffset_ListOfInterval());
502           if (aLEGA.Extent() == 2)
503           {
504             EdgeAnalyse (aEG, TopoDS::Face (aLEGA.First()), TopoDS::Face (aLEGA.Last()),
505                          aSinTol, myMapEdgeType (aEG));
506           }
507         }
508
509         // Find an edge opposite to tangential one and add ancestors for it
510         TopoDS_Edge aEOpposite;
511         for (TopExp_Explorer anExpE (aFNew, TopAbs_EDGE); anExpE.More(); anExpE.Next())
512         {
513           if (!aFNewEdgeMap.Contains (anExpE.Current()))
514           {
515             aEOpposite = TopoDS::Edge (anExpE.Current());
516             break;
517           }
518         }
519
520         {
521           // Find it in aFOpposite
522           for (TopExp_Explorer anExpE (aFToRemove, TopAbs_EDGE); anExpE.More(); anExpE.Next())
523           {
524             const TopoDS_Shape& aEInFToRem = anExpE.Current();
525             if (aE.IsSame (aEInFToRem))
526             {
527               if (BOPTools_AlgoTools::IsSplitToReverse (aEOpposite, aEInFToRem, aCtx))
528                 aEOpposite.Reverse();
529               break;
530             }
531           }
532         }
533
534         TopTools_ListOfShape aLFOpposite;
535         aLFOpposite.Append (aFNew);
536         aLFOpposite.Append (aFToRemove);
537         myAncestors.Add (aEOpposite, aLFOpposite);
538         myMapEdgeType.Bind (aEOpposite, BRepOffset_ListOfInterval());
539         EdgeAnalyse (aEOpposite, aFNew, TopoDS::Face (aFToRemove), aSinTol, myMapEdgeType (aEOpposite));
540
541         TopTools_DataMapOfShapeShape* pEEMap = myReplacement.ChangeSeek (aFToRemove);
542         if (!pEEMap)
543           pEEMap = myReplacement.Bound (aFToRemove, TopTools_DataMapOfShapeShape());
544         pEEMap->Bind (aE, aEOpposite);
545
546         // Add ancestors for the vertices
547         for (TopoDS_Iterator itV (aEOpposite); itV.More(); itV.Next())
548         {
549           const TopoDS_Shape& aV = itV.Value();
550           const TopTools_ListOfShape& aLVA = aPrismAncestors.FindFromKey (aV);
551           myAncestors.Add (aV, aLVA);
552         }
553
554         myNewFaces.Append (aFNew);
555         myGenerated.Bind (aE, aFNew);
556       }
557     }
558   }
559 }
560
561 //=======================================================================
562 //function : EdgeReplacement
563 //purpose  : 
564 //=======================================================================
565 const TopoDS_Edge& BRepOffset_Analyse::EdgeReplacement (const TopoDS_Face& theF,
566                                                         const TopoDS_Edge& theE) const
567 {
568   const TopTools_DataMapOfShapeShape* pEE = myReplacement.Seek (theF);
569   if (!pEE)
570     return theE;
571
572   const TopoDS_Shape* pE = pEE->Seek (theE);
573   if (!pE)
574     return theE;
575
576   return TopoDS::Edge (*pE);
577 }
578
579 //=======================================================================
580 //function : Generated
581 //purpose  : 
582 //=======================================================================
583 TopoDS_Shape BRepOffset_Analyse::Generated (const TopoDS_Shape& theS) const
584 {
585   static TopoDS_Shape aNullShape;
586   const TopoDS_Shape* pGenS = myGenerated.Seek (theS);
587   return pGenS ? *pGenS : aNullShape;
588 }
589
590 //=======================================================================
591 //function : Descendants
592 //purpose  : 
593 //=======================================================================
594 const TopTools_ListOfShape* BRepOffset_Analyse::Descendants (const TopoDS_Shape& theS,
595                                                              const Standard_Boolean theUpdate) const
596 {
597   if (myDescendants.IsEmpty() || theUpdate)
598   {
599     myDescendants.Clear();
600     const Standard_Integer aNbA = myAncestors.Extent();
601     for (Standard_Integer i = 1; i <= aNbA; ++i)
602     {
603       const TopoDS_Shape& aSS = myAncestors.FindKey (i);
604       const TopTools_ListOfShape& aLA = myAncestors (i);
605
606       for (TopTools_ListOfShape::Iterator it (aLA); it.More(); it.Next())
607       {
608         const TopoDS_Shape& aSA = it.Value();
609
610         TopTools_ListOfShape* pLD = myDescendants.ChangeSeek (aSA);
611         if (!pLD)
612           pLD = myDescendants.Bound (aSA, TopTools_ListOfShape());
613         if (!pLD->Contains (aSS))
614           pLD->Append (aSS);
615       }
616     }
617   }
618
619   return myDescendants.Seek (theS);
620 }
621
622 //=======================================================================
623 //function : Clear
624 //purpose  : 
625 //=======================================================================
626 void BRepOffset_Analyse::Clear()
627 {
628   myDone = Standard_False;
629   myShape     .Nullify();
630   myMapEdgeType.Clear();
631   myAncestors  .Clear();
632   myFaceOffsetMap.Clear();
633   myReplacement.Clear();
634   myDescendants.Clear();
635   myNewFaces .Clear();
636   myGenerated.Clear();
637 }
638
639 //=======================================================================
640 //function : BRepOffset_ListOfInterval&
641 //purpose  : 
642 //=======================================================================
643 const BRepOffset_ListOfInterval& BRepOffset_Analyse::Type(const TopoDS_Edge& E) const 
644 {
645   return myMapEdgeType (E);
646 }
647
648 //=======================================================================
649 //function : Edges
650 //purpose  : 
651 //=======================================================================
652 void BRepOffset_Analyse::Edges(const TopoDS_Vertex&  V, 
653                                const ChFiDS_TypeOfConcavity T,
654                                TopTools_ListOfShape& LE) const
655 {
656   LE.Clear();
657   const TopTools_ListOfShape& L = Ancestors (V);
658   TopTools_ListIteratorOfListOfShape it(L);
659   
660   for ( ;it.More(); it.Next()) {
661     const TopoDS_Edge& E = TopoDS::Edge(it.Value());
662     const BRepOffset_ListOfInterval *pIntervals = myMapEdgeType.Seek (E);
663     if (pIntervals && pIntervals->Extent() > 0)
664     {
665       TopoDS_Vertex V1,V2;
666       BRepOffset_Tool::EdgeVertices (E,V1,V2);
667       if (V1.IsSame(V)) {
668         if (pIntervals->Last().Type() == T)
669           LE.Append (E);
670       }
671       if (V2.IsSame(V)) {
672         if (pIntervals->First().Type() == T)
673           LE.Append (E);
674       }
675     }
676   }
677 }
678
679
680 //=======================================================================
681 //function : Edges
682 //purpose  : 
683 //=======================================================================
684 void BRepOffset_Analyse::Edges(const TopoDS_Face&    F, 
685                                const ChFiDS_TypeOfConcavity T,
686                                TopTools_ListOfShape& LE) const
687 {
688   LE.Clear();
689   TopExp_Explorer exp(F, TopAbs_EDGE);
690
691   for ( ;exp.More(); exp.Next()) {
692     const TopoDS_Edge& E = TopoDS::Edge(exp.Current());
693
694     const BRepOffset_ListOfInterval& Lint = Type(E);
695     BRepOffset_ListIteratorOfListOfInterval it(Lint);
696     for ( ;it.More(); it.Next()) {
697       if (it.Value().Type() == T) LE.Append(E);
698     }
699   }
700 }
701
702 //=======================================================================
703 //function : TangentEdges
704 //purpose  : 
705 //=======================================================================
706 void BRepOffset_Analyse::TangentEdges(const TopoDS_Edge&    Edge  ,
707                                       const TopoDS_Vertex&  Vertex,
708                                       TopTools_ListOfShape& Edges  ) const 
709 {
710   gp_Vec V,VRef;
711
712   Standard_Real U,URef;
713   BRepAdaptor_Curve C3d, C3dRef;
714
715   URef   = BRep_Tool::Parameter(Vertex,Edge);
716   C3dRef = BRepAdaptor_Curve(Edge);
717   VRef   = C3dRef.DN(URef,1);
718   CorrectOrientationOfTangent(VRef, Vertex, Edge);
719   if (VRef.SquareMagnitude() < gp::Resolution()) return;
720
721   Edges.Clear();
722
723   const TopTools_ListOfShape& Anc = Ancestors(Vertex);
724   TopTools_ListIteratorOfListOfShape it(Anc);
725   for ( ; it.More(); it.Next()) {
726     const TopoDS_Edge& CurE = TopoDS::Edge(it.Value());
727     if ( CurE.IsSame(Edge)) continue;
728     U   = BRep_Tool::Parameter(Vertex,CurE);
729     C3d = BRepAdaptor_Curve(CurE);
730     V   = C3d.DN(U,1);
731     CorrectOrientationOfTangent(V, Vertex, CurE);
732     if (V.SquareMagnitude() < gp::Resolution()) continue;
733     if (V.IsOpposite(VRef,myAngle)) {
734       Edges.Append(CurE);
735     }
736   }
737 }
738
739 //=======================================================================
740 //function : Explode
741 //purpose  : 
742 //=======================================================================
743 void BRepOffset_Analyse::Explode (TopTools_ListOfShape& List,
744                                   const ChFiDS_TypeOfConcavity T) const
745 {
746   List.Clear();
747   BRep_Builder B;
748   TopTools_MapOfShape Map;
749
750   TopExp_Explorer Fexp;
751   for (Fexp.Init(myShape,TopAbs_FACE); Fexp.More(); Fexp.Next()) {
752     if ( Map.Add(Fexp.Current())) {
753       TopoDS_Face Face = TopoDS::Face(Fexp.Current());
754       TopoDS_Compound Co;
755       B.MakeCompound(Co);
756       B.Add(Co,Face);
757       // add to Co all faces from the cloud of faces
758       // G1 created from <Face>
759       AddFaces(Face,Co,Map,T);
760       List.Append(Co);
761     }
762   }
763 }
764
765 //=======================================================================
766 //function : Explode
767 //purpose  : 
768 //=======================================================================
769 void BRepOffset_Analyse::Explode (TopTools_ListOfShape& List,
770                                   const ChFiDS_TypeOfConcavity T1,
771                                   const ChFiDS_TypeOfConcavity T2) const
772 {
773   List.Clear();
774   BRep_Builder B;
775   TopTools_MapOfShape Map;
776   
777   TopExp_Explorer Fexp;
778   for (Fexp.Init(myShape,TopAbs_FACE); Fexp.More(); Fexp.Next()) {
779     if ( Map.Add(Fexp.Current())) {
780       TopoDS_Face Face = TopoDS::Face(Fexp.Current());
781       TopoDS_Compound Co;
782       B.MakeCompound(Co);
783       B.Add(Co,Face);
784       // add to Co all faces from the cloud of faces
785       // G1 created from  <Face>
786       AddFaces(Face,Co,Map,T1,T2);
787       List.Append(Co);
788     }
789   }
790 }
791
792 //=======================================================================
793 //function : AddFaces
794 //purpose  : 
795 //=======================================================================
796 void BRepOffset_Analyse::AddFaces (const TopoDS_Face&    Face,
797                                    TopoDS_Compound&      Co,
798                                    TopTools_MapOfShape&  Map,
799                                    const ChFiDS_TypeOfConcavity T) const
800 {
801   BRep_Builder B;
802   const TopTools_ListOfShape *pLE = Descendants (Face);
803   if (!pLE)
804     return;
805   for (TopTools_ListOfShape::Iterator it (*pLE); it.More(); it.Next())
806   {
807     const TopoDS_Edge& E = TopoDS::Edge (it.Value());
808     const BRepOffset_ListOfInterval& LI = Type(E);
809     if (!LI.IsEmpty() && LI.First().Type() == T) {
810       // so <NewFace> is attached to G1 by <Face>
811       const TopTools_ListOfShape& L = Ancestors(E);
812       if (L.Extent() == 2) {
813         TopoDS_Face F1 = TopoDS::Face (L.First());
814         if (F1.IsSame (Face))
815           F1 = TopoDS::Face (L.Last());
816         if (Map.Add (F1)) {
817           B.Add (Co, F1);
818           AddFaces (F1, Co, Map, T);
819         }
820       }
821     }
822   }
823 }
824
825 //=======================================================================
826 //function : AddFaces
827 //purpose  : 
828 //=======================================================================
829 void BRepOffset_Analyse::AddFaces (const TopoDS_Face&    Face,
830                                    TopoDS_Compound&      Co,
831                                    TopTools_MapOfShape&  Map,
832                                    const ChFiDS_TypeOfConcavity T1,
833                                    const ChFiDS_TypeOfConcavity T2) const
834 {
835   BRep_Builder B;
836   const TopTools_ListOfShape *pLE = Descendants (Face);
837   if (!pLE)
838     return;
839   for (TopTools_ListOfShape::Iterator it (*pLE); it.More(); it.Next())
840   {
841     const TopoDS_Edge& E = TopoDS::Edge (it.Value());
842     const BRepOffset_ListOfInterval& LI = Type(E);
843     if (!LI.IsEmpty() && 
844         (LI.First().Type() == T1 || LI.First().Type() == T2)) {
845       // so <NewFace> is attached to G1 by <Face>
846       const TopTools_ListOfShape& L = Ancestors(E);
847       if (L.Extent() == 2) {
848         TopoDS_Face F1 = TopoDS::Face (L.First());
849         if (F1.IsSame (Face))
850           F1 = TopoDS::Face (L.Last());
851         if (Map.Add (F1)) {
852           B.Add (Co, F1);
853           AddFaces (F1, Co, Map, T1, T2);
854         }
855       }
856     }
857   }
858 }