1 // Created on: 2016
2 // Created by: Eugeny MALTCHIKOV
3 // Copyright (c) 2016 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15 
16 
17 // This is the implementation of the extension of the 3D offset algorithm
18 // to work in mode Complete and Join Type Intersection.
19 // Currently only the Planar cases are supported.
20 
21 
22 #include <BRepOffset_MakeOffset.hxx>
23 
24 #include <Precision.hxx>
25 #include <TopoDS.hxx>
26 
27 #include <BRepAlgo_AsDes.hxx>
28 #include <BRepAlgo_Image.hxx>
29 
30 #include <BRep_Builder.hxx>
31 #include <BRep_Tool.hxx>
32 
33 #include <BRepLib.hxx>
34 #include <BRepTools.hxx>
35 
36 #include <BRepAdaptor_Curve.hxx>
37 
38 #include <TopExp.hxx>
39 #include <TopExp_Explorer.hxx>
40 
41 #include <TopTools_DataMapOfShapeInteger.hxx>
42 
43 #include <BRepOffset_Tool.hxx>
44 
45 #include <BRepClass3d_SolidClassifier.hxx>
46 
47 #include <BOPDS_DS.hxx>
48 
49 #include <BOPAlgo_Builder.hxx>
50 #include <BOPAlgo_BuilderFace.hxx>
51 #include <BOPAlgo_MakerVolume.hxx>
52 #include <BOPAlgo_PaveFiller.hxx>
53 #include <BOPAlgo_Section.hxx>
54 #include <BOPAlgo_Splitter.hxx>
55 
56 #include <TopTools_ListOfShape.hxx>
57 #include <TopTools_DataMapOfShapeShape.hxx>
58 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
59 #include <TopTools_MapOfOrientedShape.hxx>
60 
61 #include <BOPTools_AlgoTools3D.hxx>
62 #include <BOPTools_AlgoTools.hxx>
63 #include <BOPTools_AlgoTools2D.hxx>
64 #include <BOPTools_Set.hxx>
65 
66 #include <IntTools_Context.hxx>
67 #include <IntTools_ShrunkRange.hxx>
68 
69 #ifdef OFFSET_DEBUG
70 #include <BRepAlgoAPI_Check.hxx>
71 #endif
72 
73 typedef NCollection_DataMap<TopoDS_Shape,
74   TopTools_MapOfShape,
75   TopTools_ShapeMapHasher> BRepOffset_DataMapOfShapeMapOfShape;
76 
77 typedef NCollection_DataMap<TopoDS_Shape,
78   TopTools_IndexedMapOfShape,
79   TopTools_ShapeMapHasher> BRepOffset_DataMapOfShapeIndexedMapOfShape;
80 
81 
82 namespace {
83 
84   //=======================================================================
85   //function : AddToContainer
86   //purpose  : Set of methods to add a shape into container
87   //=======================================================================
AddToContainer(const TopoDS_Shape & theS,TopTools_ListOfShape & theList)88   static void AddToContainer (const TopoDS_Shape& theS,
89                               TopTools_ListOfShape& theList)
90   {
91     theList.Append (theS);
92   }
AddToContainer(const TopoDS_Shape & theS,TopTools_MapOfShape & theMap)93   static Standard_Boolean AddToContainer (const TopoDS_Shape& theS,
94                                           TopTools_MapOfShape& theMap)
95   {
96     return theMap.Add (theS);
97   }
AddToContainer(const TopoDS_Shape & theS,TopTools_IndexedMapOfShape & theMap)98   static Standard_Boolean AddToContainer (const TopoDS_Shape& theS,
99                                           TopTools_IndexedMapOfShape& theMap)
100   {
101     const Standard_Integer aNb = theMap.Extent();
102     const Standard_Integer anInd = theMap.Add (theS);
103     return anInd > aNb;
104   }
AddToContainer(const TopoDS_Shape & theS,TopoDS_Shape & theSOut)105   static void AddToContainer (const TopoDS_Shape& theS,
106                               TopoDS_Shape& theSOut)
107   {
108     BRep_Builder().Add (theSOut, theS);
109   }
110 
111   //=======================================================================
112   //function : TakeModified
113   //purpose  : Check if the shape has images in the given images map.
114   //           Puts in the output map either the images or the shape itself.
115   //=======================================================================
116   template <class ContainerType, class FenceMapType>
TakeModified(const TopoDS_Shape & theS,const TopTools_DataMapOfShapeListOfShape & theImages,ContainerType & theContainer,FenceMapType * theMFence)117   static Standard_Boolean TakeModified (const TopoDS_Shape& theS,
118                                         const TopTools_DataMapOfShapeListOfShape& theImages,
119                                         ContainerType& theContainer,
120                                         FenceMapType* theMFence)
121   {
122     const TopTools_ListOfShape* pLSIm = theImages.Seek (theS);
123     if (pLSIm)
124     {
125       TopTools_ListIteratorOfListOfShape itLSIm (*pLSIm);
126       for (; itLSIm.More(); itLSIm.Next())
127       {
128         const TopoDS_Shape& aSIm = itLSIm.Value();
129         if (!theMFence || AddToContainer (aSIm, *theMFence))
130           AddToContainer (aSIm, theContainer);
131       }
132       return Standard_True;
133     }
134     else
135     {
136       if (!theMFence || AddToContainer (theS, *theMFence))
137         AddToContainer (theS, theContainer);
138       return Standard_False;
139     }
140   }
141 
142   template <class ContainerType>
TakeModified(const TopoDS_Shape & theS,const TopTools_DataMapOfShapeListOfShape & theImages,ContainerType & theMapOut)143   static Standard_Boolean TakeModified (const TopoDS_Shape& theS,
144                                         const TopTools_DataMapOfShapeListOfShape& theImages,
145                                         ContainerType& theMapOut)
146   {
147     TopTools_MapOfShape* aDummy = NULL;
148     return TakeModified (theS, theImages, theMapOut, aDummy);
149   }
150 
151   //=======================================================================
152   //function : hasData
153   //purpose  : Checks if container has any data in it
154   //=======================================================================
155   template <class Container>
hasData(const Container * theData)156   static Standard_Boolean hasData (const Container* theData)
157   {
158     return (theData && !theData->IsEmpty());
159   }
160 
161   //=======================================================================
162   //function : AppendToList
163   //purpose  : Add to a list only unique elements
164   //=======================================================================
AppendToList(TopTools_ListOfShape & theList,const TopoDS_Shape & theShape)165   static void AppendToList (TopTools_ListOfShape& theList,
166                             const TopoDS_Shape& theShape)
167   {
168     for (TopTools_ListOfShape::Iterator it (theList); it.More(); it.Next())
169     {
170       const TopoDS_Shape& aS = it.Value();
171       if (aS.IsSame (theShape))
172       {
173         return;
174       }
175     }
176     theList.Append (theShape);
177   }
178 
179   //=======================================================================
180   //function : ProcessMicroEdge
181   //purpose  : Checking if the edge is micro edge
182   //=======================================================================
ProcessMicroEdge(const TopoDS_Edge & theEdge,const Handle (IntTools_Context)& theCtx)183   static Standard_Boolean ProcessMicroEdge (const TopoDS_Edge& theEdge,
184                                             const Handle(IntTools_Context)& theCtx)
185   {
186     TopoDS_Vertex aV1, aV2;
187     TopExp::Vertices (theEdge, aV1, aV2);
188     if (aV1.IsNull() || aV2.IsNull())
189     {
190       return Standard_False;
191     }
192 
193     Standard_Boolean bMicro = BOPTools_AlgoTools::IsMicroEdge (theEdge, theCtx);
194     if (bMicro && BRepAdaptor_Curve (theEdge).GetType() == GeomAbs_Line)
195     {
196       Standard_Real aLen = BRep_Tool::Pnt (aV1).Distance (BRep_Tool::Pnt (aV2));
197       BRep_Builder().UpdateVertex (aV1, aLen / 2.);
198       BRep_Builder().UpdateVertex (aV2, aLen / 2.);
199     }
200 
201     return bMicro;
202   }
203 
204   //=======================================================================
205   //function : UpdateOrigins
206   //purpose  : Updating origins
207   //=======================================================================
UpdateOrigins(const TopTools_ListOfShape & theLA,TopTools_DataMapOfShapeListOfShape & theOrigins,BOPAlgo_Builder & theGF)208   static void UpdateOrigins (const TopTools_ListOfShape& theLA,
209                              TopTools_DataMapOfShapeListOfShape& theOrigins,
210                              BOPAlgo_Builder& theGF)
211   {
212     for (TopTools_ListOfShape::Iterator aItA (theLA); aItA.More(); aItA.Next())
213     {
214       const TopoDS_Shape& aS = aItA.Value();
215 
216       const TopTools_ListOfShape& aLSIm = theGF.Modified (aS);
217       if (aLSIm.IsEmpty())
218       {
219         continue;
220       }
221 
222       TopTools_ListOfShape aLSEmpt;
223       TopTools_ListOfShape* pLS = theOrigins.ChangeSeek (aS);
224       if (!pLS)
225       {
226         pLS = &aLSEmpt;
227         pLS->Append (aS);
228       }
229 
230       for (TopTools_ListOfShape::Iterator aIt (aLSIm); aIt.More(); aIt.Next())
231       {
232         const TopoDS_Shape& aSIm = aIt.Value();
233         if (TopTools_ListOfShape* pLSOr = theOrigins.ChangeSeek (aSIm))
234         {
235           // merge two lists
236           for (TopTools_ListOfShape::Iterator aIt1 (*pLS); aIt1.More(); aIt1.Next())
237           {
238             AppendToList (*pLSOr, aIt1.Value());
239           }
240         }
241         else
242         {
243           theOrigins.Bind (aSIm, *pLS);
244         }
245       }
246     }
247   }
248 
249   //=======================================================================
250   //function : UpdateImages
251   //purpose  : Updating images of the shapes
252   //=======================================================================
UpdateImages(const TopTools_ListOfShape & theLA,TopTools_DataMapOfShapeListOfShape & theImages,BOPAlgo_Builder & theGF,TopTools_MapOfShape & theModified)253   static void UpdateImages (const TopTools_ListOfShape& theLA,
254                             TopTools_DataMapOfShapeListOfShape& theImages,
255                             BOPAlgo_Builder& theGF,
256                             TopTools_MapOfShape& theModified)
257   {
258     for (TopTools_ListOfShape::Iterator aIt (theLA); aIt.More(); aIt.Next())
259     {
260       const TopoDS_Shape& aS = aIt.Value();
261 
262       TopTools_ListOfShape* pLSIm = theImages.ChangeSeek (aS);
263       if (!pLSIm)
264       {
265         const TopTools_ListOfShape& aLSIm = theGF.Modified (aS);
266         if (aLSIm.Extent())
267         {
268           theImages.Bind (aS, aLSIm);
269           theModified.Add (aS);
270         }
271         continue;
272       }
273 
274       TopTools_MapOfShape aMFence;
275       TopTools_ListOfShape aLSImNew;
276 
277       Standard_Boolean bModified = Standard_False;
278 
279       // check modifications of the images
280       for (TopTools_ListOfShape::Iterator aIt1 (*pLSIm); aIt1.More(); aIt1.Next())
281       {
282         const TopoDS_Shape& aSIm = aIt1.Value();
283         bModified |= TakeModified (aSIm, theGF.Images(), aLSImNew, &aMFence);
284       }
285 
286       if (bModified)
287       {
288         *pLSIm = aLSImNew;
289         theModified.Add (aS);
290       }
291     }
292   }
293 
294   //=======================================================================
295   //function : FindCommonParts
296   //purpose  : Looking for the parts of type <theType> contained in both lists
297   //=======================================================================
FindCommonParts(const TopTools_ListOfShape & theLS1,const TopTools_ListOfShape & theLS2,TopTools_ListOfShape & theLSC,const TopAbs_ShapeEnum theType=TopAbs_EDGE)298   static void FindCommonParts (const TopTools_ListOfShape& theLS1,
299                                const TopTools_ListOfShape& theLS2,
300                                TopTools_ListOfShape& theLSC,
301                                const TopAbs_ShapeEnum theType = TopAbs_EDGE)
302   {
303     // map shapes in the first list
304     TopTools_IndexedMapOfShape aMS1;
305     for (TopTools_ListOfShape::Iterator aIt (theLS1); aIt.More(); aIt.Next())
306     {
307       const TopoDS_Shape& aS = aIt.Value();
308       TopExp::MapShapes (aS, theType, aMS1);
309     }
310     if (aMS1.IsEmpty())
311     {
312       return;
313     }
314 
315     // check for such shapes in the other list
316     TopTools_MapOfShape aMFence;
317     for (TopTools_ListOfShape::Iterator aIt (theLS2); aIt.More(); aIt.Next())
318     {
319       const TopoDS_Shape& aS = aIt.Value();
320 
321       TopExp_Explorer aExp (aS, theType);
322       for (; aExp.More(); aExp.Next())
323       {
324         const TopoDS_Shape& aST = aExp.Current();
325         if (aMS1.Contains (aST) && aMFence.Add (aST))
326         {
327           theLSC.Append (aST);
328         }
329       }
330     }
331   }
332 
333   //=======================================================================
334   //function : NbPoints
335   //purpose  : Defines number of sample points to get average direction of the edge
336   //=======================================================================
NbPoints(const TopoDS_Edge & theEdge)337   static Standard_Integer NbPoints (const TopoDS_Edge& theEdge)
338   {
339     BRepAdaptor_Curve aBAC (theEdge);
340     switch (aBAC.GetType())
341     {
342     case GeomAbs_Line:
343       return 1;
344     default:
345       return 11;
346     }
347   }
348 
349   //=======================================================================
350   //function : FindShape
351   //purpose  : Looking for the same sub-shape in the shape
352   //=======================================================================
FindShape(const TopoDS_Shape & theSWhat,const TopoDS_Shape & theSWhere,const BRepOffset_Analyse * theAnalyse,TopoDS_Shape & theRes)353   static Standard_Boolean FindShape (const TopoDS_Shape& theSWhat,
354                                      const TopoDS_Shape& theSWhere,
355                                      const BRepOffset_Analyse* theAnalyse,
356                                      TopoDS_Shape& theRes)
357   {
358     Standard_Boolean bFound = Standard_False;
359     TopAbs_ShapeEnum aType = theSWhat.ShapeType();
360     TopExp_Explorer aExp (theSWhere, aType);
361     for (; aExp.More(); aExp.Next())
362     {
363       const TopoDS_Shape& aS = aExp.Current();
364       if (aS.IsSame (theSWhat))
365       {
366         theRes = aS;
367         bFound = Standard_True;
368         break;
369       }
370     }
371 
372     if (!bFound && theAnalyse)
373     {
374       const TopTools_ListOfShape* pLD = theAnalyse->Descendants (theSWhere);
375       if (pLD)
376       {
377         for (TopTools_ListOfShape::Iterator it (*pLD); it.More(); it.Next())
378         {
379           const TopoDS_Shape& aS = it.Value();
380           if (aS.IsSame (theSWhat))
381           {
382             theRes = aS;
383             bFound = Standard_True;
384             break;
385           }
386         }
387       }
388     }
389 
390     return bFound;
391   }
392 
393   //=======================================================================
394   //function : BuildSplitsOfTrimmedFace
395   //purpose  : Building the splits of offset face
396   //=======================================================================
BuildSplitsOfTrimmedFace(const TopoDS_Face & theFace,const TopoDS_Shape & theEdges,TopTools_ListOfShape & theLFImages,const Message_ProgressRange & theRange)397   static void BuildSplitsOfTrimmedFace (const TopoDS_Face& theFace,
398                                         const TopoDS_Shape& theEdges,
399                                         TopTools_ListOfShape& theLFImages,
400                                         const Message_ProgressRange& theRange)
401   {
402     BOPAlgo_Splitter aSplitter;
403     //
404     aSplitter.AddArgument (theFace);
405     aSplitter.AddArgument (theEdges);
406     aSplitter.SetToFillHistory (Standard_False);
407     aSplitter.Perform (theRange);
408     if (aSplitter.HasErrors())
409     {
410       return;
411     }
412     //
413     // splits of the offset shape
414     for (TopExp_Explorer anExp (aSplitter.Shape(), TopAbs_FACE); anExp.More(); anExp.Next())
415     {
416       theLFImages.Append (anExp.Current());
417     }
418   }
419 
420   //=======================================================================
421   //function : BuildSplitsOfFace
422   //purpose  : Building the splits of offset face
423   //=======================================================================
BuildSplitsOfFace(const TopoDS_Face & theFace,const TopoDS_Shape & theEdges,TopTools_DataMapOfShapeShape & theFacesOrigins,TopTools_ListOfShape & theLFImages)424   static void BuildSplitsOfFace (const TopoDS_Face& theFace,
425                                  const TopoDS_Shape& theEdges,
426                                  TopTools_DataMapOfShapeShape& theFacesOrigins,
427                                  TopTools_ListOfShape& theLFImages)
428   {
429     theLFImages.Clear();
430     //
431     // take edges to split the face
432     TopTools_ListOfShape aLE;
433     TopExp_Explorer aExp (theEdges, TopAbs_EDGE);
434     for (; aExp.More(); aExp.Next())
435     {
436       TopoDS_Edge aE = TopoDS::Edge (aExp.Current());
437       aE.Orientation (TopAbs_FORWARD);
438       aLE.Append (aE);
439       aE.Orientation (TopAbs_REVERSED);
440       aLE.Append (aE);
441     }
442     //
443     TopoDS_Face aFF = theFace;
444     TopAbs_Orientation anOr = theFace.Orientation();
445     aFF.Orientation (TopAbs_FORWARD);
446     //
447     // build pcurves for edges on the face
448     BRepLib::BuildPCurveForEdgesOnPlane (aLE, aFF);
449     //
450     // build splits of faces
451     BOPAlgo_BuilderFace aBF;
452     aBF.SetFace (aFF);
453     aBF.SetShapes (aLE);
454     aBF.Perform();
455     if (aBF.HasErrors())
456     {
457       return;
458     }
459     //
460     const TopTools_ListOfShape& aLFSp = aBF.Areas();
461     TopTools_ListIteratorOfListOfShape aItLF (aLFSp);
462     for (; aItLF.More(); aItLF.Next())
463     {
464       TopoDS_Shape& aFSp = aItLF.ChangeValue();
465       aFSp.Orientation (anOr);
466       theLFImages.Append (aFSp);
467       //
468       theFacesOrigins.Bind (aFSp, theFace);
469     }
470   }
471 
472   //=======================================================================
473   //function : GetAverageTangent
474   //purpose  : Computes average tangent vector along the curve
475   //=======================================================================
GetAverageTangent(const TopoDS_Shape & theS,const Standard_Integer theNbP)476   static gp_Vec GetAverageTangent (const TopoDS_Shape& theS,
477                                    const Standard_Integer theNbP)
478   {
479     gp_Vec aVA;
480     TopExp_Explorer aExp (theS, TopAbs_EDGE);
481     for (; aExp.More(); aExp.Next())
482     {
483       const TopoDS_Edge& aE = *(TopoDS_Edge*)&aExp.Current();
484       //
485       Standard_Real aT1, aT2;
486       const Handle(Geom_Curve)& aC = BRep_Tool::Curve (aE, aT1, aT2);
487       //
488       gp_Pnt aP;
489       gp_Vec aV, aVSum;
490       Standard_Real aT = aT1;
491       Standard_Real aDt = (aT2 - aT1) / theNbP;
492       while (aT <= aT2)
493       {
494         aC->D1 (aT, aP, aV);
495         aVSum += aV.Normalized();
496         aT += aDt;
497       }
498       //
499       if (aE.Orientation() == TopAbs_REVERSED)
500       {
501         aVSum.Reverse();
502       }
503       //
504       aVA += aVSum;
505     }
506     return aVA;
507   }
508 }
509 
510 //=======================================================================
511 //function : BRepOffset_BuildOffsetFaces
512 //purpose  : Auxiliary local class that is used here for building splits
513 //           of offset faces, that are further used for building volumes.
514 //=======================================================================
515 class BRepOffset_BuildOffsetFaces
516 {
517 public: //! @name Constructor
518   //! Constructor, taking the history tool to be filled
BRepOffset_BuildOffsetFaces(BRepAlgo_Image & theImage)519   BRepOffset_BuildOffsetFaces (BRepAlgo_Image& theImage) :
520     myFaces (NULL),
521     myAnalyzer (NULL),
522     myEdgesOrigins (NULL),
523     myFacesOrigins (NULL),
524     myETrimEInf (NULL),
525     myImage (&theImage)
526   {
527     myContext = new IntTools_Context();
528   }
529 
530 public: //! @name Setting data
531 
532   //! Sets faces to build splits
SetFaces(const TopTools_ListOfShape & theFaces)533   void SetFaces (const TopTools_ListOfShape& theFaces) { myFaces = &theFaces; }
534 
535   //! Sets ascendants/descendants information
SetAsDesInfo(const Handle (BRepAlgo_AsDes)& theAsDes)536   void SetAsDesInfo (const Handle(BRepAlgo_AsDes)& theAsDes) { myAsDes = theAsDes; }
537 
538   //! Sets the analysis info of the input shape
SetAnalysis(const BRepOffset_Analyse & theAnalyse)539   void SetAnalysis (const BRepOffset_Analyse& theAnalyse) { myAnalyzer = &theAnalyse; }
540 
541   //! Sets origins of the offset edges (from original shape)
SetEdgesOrigins(TopTools_DataMapOfShapeListOfShape & theEdgesOrigins)542   void SetEdgesOrigins (TopTools_DataMapOfShapeListOfShape& theEdgesOrigins) { myEdgesOrigins = &theEdgesOrigins; }
543 
544   //! Sets origins of the offset faces (from original shape)
SetFacesOrigins(TopTools_DataMapOfShapeShape & theFacesOrigins)545   void SetFacesOrigins (TopTools_DataMapOfShapeShape& theFacesOrigins) { myFacesOrigins = &theFacesOrigins; }
546 
547   //! Sets infinite (extended) edges for the trimmed ones
SetInfEdges(TopTools_DataMapOfShapeShape & theETrimEInf)548   void SetInfEdges (TopTools_DataMapOfShapeShape& theETrimEInf) { myETrimEInf = &theETrimEInf; }
549 
550 public: //! @name Public methods to build the splits
551 
552   //! Build splits of already trimmed faces
553   void BuildSplitsOfTrimmedFaces (const Message_ProgressRange& theRange);
554 
555   //! Building splits of not-trimmed offset faces.
556   //! For the cases in which invalidities will be found, these invalidities will be rebuilt.
557   void BuildSplitsOfExtendedFaces (const Message_ProgressRange& theRange);
558 
559 private: //! @name private methods performing the job
560 
561 private: //! @name Intersection and post-treatment of edges
562 
563   //! Intersection of the trimmed edges among themselves
564   void IntersectTrimmedEdges (const Message_ProgressRange& theRange);
565 
566   //! Saving connection from trimmed edges to not trimmed ones
567   void UpdateIntersectedEdges (const TopTools_ListOfShape& theLA,
568                                BOPAlgo_Builder& theGF);
569 
570   //! Getting edges from AsDes map to build the splits of faces
571   Standard_Boolean GetEdges (const TopoDS_Face& theFace,
572                              TopoDS_Shape& theEdges,
573                              TopTools_IndexedMapOfShape* theInv = nullptr);
574 
575   //! Looks for the invalid edges (edges with changed orientation)
576   //! in the splits of offset faces
577   void FindInvalidEdges (const TopoDS_Face& theF,
578                          const TopTools_ListOfShape& theLFImages,
579                          BRepOffset_DataMapOfShapeMapOfShape& theDMFMVE,
580                          BRepOffset_DataMapOfShapeMapOfShape& theDMFMNE,
581                          BRepOffset_DataMapOfShapeIndexedMapOfShape& theDMFMIE,
582                          BRepOffset_DataMapOfShapeMapOfShape& theDMFMVIE,
583                          TopTools_DataMapOfShapeListOfShape& theDMEOrLEIm,
584                          TopTools_MapOfShape& theEdgesInvalidByVertex,
585                          TopTools_MapOfShape& theEdgesValidByVertex,
586                          const Message_ProgressRange& theRange);
587 
588   //! Additional method to look for invalid edges
589   void FindInvalidEdges (const TopTools_ListOfShape& theLFOffset,
590                          BRepOffset_DataMapOfShapeIndexedMapOfShape& theLocInvEdges,
591                          BRepOffset_DataMapOfShapeMapOfShape& theLocValidEdges,
592                          BRepOffset_DataMapOfShapeMapOfShape& theNeutralEdges);
593 
594   //! Checks if the edge has been inverted
595   Standard_Boolean CheckInverted (const TopoDS_Edge& theEIm,
596                                   const TopoDS_Face& theFOr,
597                                   const TopTools_IndexedDataMapOfShapeListOfShape& theDMVE,
598                                   const TopTools_IndexedMapOfShape& theMEdges);
599 
600   //! Looking for the invalid faces containing inverted edges that can be safely removed
601   void RemoveInvalidSplitsByInvertedEdges (TopTools_IndexedMapOfShape& theMERemoved);
602 
603   //! Makes inverted edges located inside loop of invalid edges, invalid as well
604   void MakeInvertedEdgesInvalid (const TopTools_ListOfShape& theLFOffset);
605 
606   //! Checks if it is possible to remove the block containing inverted edges
607   Standard_Boolean CheckInvertedBlock (const TopoDS_Shape& theCB,
608                                        const TopTools_ListOfShape& theLCBF,
609                                        BRepOffset_DataMapOfShapeMapOfShape& theDMCBVInverted,
610                                        BRepOffset_DataMapOfShapeMapOfShape& theDMCBVAll);
611 
612   //! Updating the maps of images and origins of the offset edges
613   void FilterEdgesImages (const TopoDS_Shape& theS);
614 
615   //! Checks additionally the unchecked edges originated from vertices
616   void CheckEdgesCreatedByVertex();
617 
618   //! Filtering the invalid edges according to currently invalid faces
619   void FilterInvalidEdges (const BRepOffset_DataMapOfShapeIndexedMapOfShape& theDMFMIE,
620                            const TopTools_IndexedMapOfShape& theMERemoved);
621 
622 private: //! @name Checking faces
623 
624   //! Build splits of faces
625   void BuildSplitsOfFaces (const Message_ProgressRange& theRange);
626 
627   //! Looking for the invalid faces by analyzing their invalid edges
628   void FindInvalidFaces (TopTools_ListOfShape& theLFImages,
629                          const BRepOffset_DataMapOfShapeMapOfShape& theDMFMVE,
630                          const BRepOffset_DataMapOfShapeIndexedMapOfShape& theDMFMIE,
631                          const TopTools_MapOfShape& theMENeutral,
632                          const TopTools_MapOfShape& theEdgesInvalidByVertex,
633                          const TopTools_MapOfShape& theEdgesValidByVertex,
634                          const TopTools_MapOfShape& theMFHoles,
635                          TopTools_IndexedMapOfShape& theMFInvInHole,
636                          TopTools_ListOfShape& theInvFaces,
637                          TopTools_ListOfShape& theInvertedFaces);
638 
639   //! Find faces inside holes wires from the original face
640   void FindFacesInsideHoleWires (const TopoDS_Face& theFOrigin,
641                                  const TopoDS_Face& theFOffset,
642                                  const TopTools_ListOfShape& theLFImages,
643                                  const TopTools_DataMapOfShapeListOfShape& theDMEOrLEIm,
644                                  const TopTools_IndexedDataMapOfShapeListOfShape& theEFMap,
645                                  TopTools_MapOfShape& theMFHoles);
646 
647   //! Removing invalid splits of faces from valid
648   void RemoveInvalidSplitsFromValid (const BRepOffset_DataMapOfShapeMapOfShape& theDMFMVIE);
649 
650   //! Looking for the inside faces that can be safely removed
651   void RemoveInsideFaces (const TopTools_ListOfShape& theInvertedFaces,
652                           const TopTools_IndexedMapOfShape& theMFToCheckInt,
653                           const TopTools_IndexedMapOfShape& theMFInvInHole,
654                           const TopoDS_Shape& theFHoles,
655                           TopTools_IndexedMapOfShape& theMERemoved,
656                           TopTools_IndexedMapOfShape& theMEInside,
657                           const Message_ProgressRange& theRange);
658 
659   //! Looking for the connections between faces not to miss some necessary intersection
660   void ShapesConnections (const TopTools_DataMapOfShapeShape& theDMFOr,
661                           BOPAlgo_Builder& theBuilder);
662 
663   //! Remove isolated invalid hanging parts
664   void RemoveHangingParts (const BOPAlgo_MakerVolume& theMV,
665                            const TopTools_DataMapOfShapeShape& theDMFImF,
666                            const TopTools_IndexedMapOfShape& theMFInv,
667                            TopTools_MapOfShape& theMFToRem);
668 
669   //! Removing valid splits according to results of intersection
670   void RemoveValidSplits (const TopTools_MapOfShape& theSpRem,
671                           BOPAlgo_Builder& theGF,
672                           TopTools_IndexedMapOfShape& theMERemoved);
673 
674   //! Removing invalid splits according to the results of intersection
675   void RemoveInvalidSplits (const TopTools_MapOfShape& theSpRem,
676                             BOPAlgo_Builder& theGF,
677                             TopTools_IndexedMapOfShape& theMERemoved);
678 
679   //! Filtering of the invalid faces
680   void FilterInvalidFaces (const TopTools_IndexedDataMapOfShapeListOfShape& theDMEF,
681                            const TopTools_IndexedMapOfShape& theMERemoved);
682 
683   //! Checks if the face is artificially invalid
684   Standard_Boolean CheckIfArtificial (const TopoDS_Shape& theF,
685                                       const TopTools_ListOfShape& theLFImages,
686                                       const TopoDS_Shape& theCE,
687                                       const TopTools_IndexedMapOfShape& theMapEInv,
688                                       TopTools_MapOfShape& theMENInv);
689 
690   //! Looking for the faces that have to be rebuilt:
691   //! * Faces close to invalidity
692   //! * Faces containing some invalid parts
693   void FindFacesToRebuild();
694 
695   //! Intersection of the faces that should be rebuild to resolve all invalidities
696   void IntersectFaces (TopTools_MapOfShape& theVertsToAvoid,
697                        const Message_ProgressRange& theRange);
698 
699   //! Preparation of the maps for analyzing intersections of the faces
700   void PrepareFacesForIntersection (const Standard_Boolean theLookVertToAvoid,
701                                     TopTools_IndexedDataMapOfShapeListOfShape& theFLE,
702                                     TopTools_DataMapOfShapeListOfShape& theMDone,
703                                     TopTools_DataMapOfShapeListOfShape& theDMSF,
704                                     TopTools_DataMapOfShapeListOfShape& theMEInfETrim,
705                                     TopTools_DataMapOfShapeListOfShape& theDMVEFull,
706                                     TopTools_IndexedDataMapOfShapeListOfShape& theDMEFInv);
707 
708   //! Looking for the invalid vertices
709   void FindVerticesToAvoid (const TopTools_IndexedDataMapOfShapeListOfShape& theDMEFInv,
710                             const TopTools_DataMapOfShapeListOfShape& theDMVEFull,
711                             TopTools_MapOfShape& theMVRInv);
712 
713   //! Looking for the faces around each invalidity for intersection
714   void FindFacesForIntersection (const TopoDS_Shape& theFInv,
715                                  const TopTools_IndexedMapOfShape& theME,
716                                  const TopTools_DataMapOfShapeListOfShape& theDMSF,
717                                  const TopTools_MapOfShape& theMVInvAll,
718                                  const Standard_Boolean theArtCase,
719                                  TopTools_IndexedMapOfShape& theMFAvoid,
720                                  TopTools_IndexedMapOfShape& theMFInt,
721                                  TopTools_IndexedMapOfShape& theMFIntExt,
722                                  TopTools_ListOfShape& theLFImInt);
723 
724   //! Analyzing the common edges between splits of offset faces
725   void ProcessCommonEdges (const TopTools_ListOfShape& theLEC,
726                            const TopTools_IndexedMapOfShape& theME,
727                            const TopTools_DataMapOfShapeListOfShape& theMEInfETrim,
728                            const TopTools_MapOfShape& theAllInvs,
729                            const Standard_Boolean theForceUse,
730                            TopTools_IndexedMapOfShape& theMECV,
731                            TopTools_MapOfShape& theMECheckExt,
732                            TopTools_DataMapOfShapeListOfShape& theDMEETrim,
733                            TopTools_ListOfShape& theLFEi,
734                            TopTools_ListOfShape& theLFEj,
735                            TopTools_IndexedMapOfShape& theMEToInt);
736 
737   //! Updating the already interfered faces
738   void UpdateIntersectedFaces (const TopoDS_Shape& theFInv,
739                                const TopoDS_Shape& theFi,
740                                const TopoDS_Shape& theFj,
741                                const TopTools_ListOfShape& theLFInv,
742                                const TopTools_ListOfShape& theLFImi,
743                                const TopTools_ListOfShape& theLFImj,
744                                const TopTools_ListOfShape& theLFEi,
745                                const TopTools_ListOfShape& theLFEj,
746                                TopTools_IndexedMapOfShape& theMEToInt);
747 
748   //! Intersection of the pair of faces
749   void IntersectFaces (const TopoDS_Shape& theFInv,
750                        const TopoDS_Shape& theFi,
751                        const TopoDS_Shape& theFj,
752                        const TopTools_ListOfShape& theLFInv,
753                        const TopTools_ListOfShape& theLFImi,
754                        const TopTools_ListOfShape& theLFImj,
755                        TopTools_ListOfShape& theLFEi,
756                        TopTools_ListOfShape& theLFEj,
757                        TopTools_IndexedMapOfShape& theMECV,
758                        TopTools_IndexedMapOfShape& theMEToInt);
759 
760   //! Intersection of the new intersection edges among themselves
761   void IntersectAndTrimEdges (const TopTools_IndexedMapOfShape& theMFInt,
762                               const TopTools_IndexedMapOfShape& theMEInt,
763                               const TopTools_DataMapOfShapeListOfShape& theDMEETrim,
764                               const TopTools_IndexedMapOfShape& theMSInv,
765                               const TopTools_IndexedMapOfShape& theMVE,
766                               const TopTools_MapOfShape& theVertsToAvoid,
767                               const TopTools_MapOfShape& theNewVertsToAvoid,
768                               const TopTools_MapOfShape& theMECheckExt,
769                               TopTools_MapOfShape& theMVBounds,
770                               TopTools_DataMapOfShapeListOfShape& theEImages);
771 
772   //! Looking for the invalid edges by intersecting with invalid vertices
773   void GetInvalidEdges (const TopTools_MapOfShape& theVertsToAvoid,
774                         const TopTools_MapOfShape& theMVBounds,
775                         BOPAlgo_Builder& theGF,
776                         TopTools_MapOfShape& theMEInv);
777 
778   //! Making the new splits and updating the maps
779   void UpdateValidEdges (const TopTools_IndexedDataMapOfShapeListOfShape& theFLE,
780                          const TopTools_IndexedDataMapOfShapeListOfShape& theOENEdges,
781                          const TopTools_MapOfShape& theMVBounds,
782                          const TopTools_MapOfShape& theMEInvOnArt,
783                          TopTools_MapOfShape& theMECheckExt,
784                          TopTools_MapOfShape& theVertsToAvoid,
785                          TopTools_DataMapOfShapeListOfShape& theEImages,
786                          TopTools_DataMapOfShapeListOfShape& theEETrim,
787                          const Message_ProgressRange& theRange);
788 
789   //! Trims intersection edges
790   void TrimNewIntersectionEdges (const TopTools_ListOfShape& theLE,
791                                  const TopTools_DataMapOfShapeListOfShape& theEETrim,
792                                  const TopTools_MapOfShape& theMVBounds,
793                                  TopTools_MapOfShape& theMECheckExt,
794                                  TopTools_DataMapOfShapeListOfShape& theEImages,
795                                  TopTools_MapOfShape& theMEB,
796                                  TopTools_MapOfShape& theMVOld,
797                                  TopTools_MapOfShape& theMENew,
798                                  TopTools_DataMapOfShapeListOfShape& theDMEOr,
799                                  TopTools_DataMapOfShapeListOfShape& theMELF);
800 
801   //! Intersecting the trimmed edges to avoid self-intersections
802   void IntersectEdges (const TopTools_ListOfShape& theLA,
803                        const TopTools_ListOfShape& theLE,
804                        const TopTools_MapOfShape& theMVBounds,
805                        const TopTools_MapOfShape& theVertsToAvoid,
806                        TopTools_MapOfShape& theMENew,
807                        TopTools_MapOfShape& theMECheckExt,
808                        TopTools_DataMapOfShapeListOfShape& theEImages,
809                        TopTools_DataMapOfShapeListOfShape& theDMEOr,
810                        TopTools_DataMapOfShapeListOfShape& theMELF,
811                        TopoDS_Shape& theSplits);
812 
813   //! Getting edges from the splits of offset faces
814   void GetBounds (const TopTools_ListOfShape& theLFaces,
815                   const TopTools_MapOfShape& theMEB,
816                   TopoDS_Shape& theBounds);
817 
818   //! Get bounding edges that should be updated
819   void GetBoundsToUpdate (const TopTools_ListOfShape& theLF,
820                           const TopTools_MapOfShape& theMEB,
821                           TopTools_ListOfShape& theLABounds,
822                           TopTools_ListOfShape& theLAValid,
823                           TopoDS_Shape& theBounds);
824 
825   //! Filter new splits by intersection with bounds
826   void GetInvalidEdgesByBounds (const TopoDS_Shape& theSplits,
827                                 const TopoDS_Shape& theBounds,
828                                 const TopTools_MapOfShape& theMVOld,
829                                 const TopTools_MapOfShape& theMENew,
830                                 const TopTools_DataMapOfShapeListOfShape& theDMEOr,
831                                 const TopTools_DataMapOfShapeListOfShape& theMELF,
832                                 const TopTools_DataMapOfShapeListOfShape& theEImages,
833                                 const TopTools_MapOfShape& theMECheckExt,
834                                 const TopTools_MapOfShape& theMEInvOnArt,
835                                 TopTools_MapOfShape& theVertsToAvoid,
836                                 TopTools_MapOfShape& theMEInv);
837 
838   //! Filter the images of edges from the invalid edges
839   void FilterSplits (const TopTools_ListOfShape& theLE,
840                      const TopTools_MapOfShape& theMEFilter,
841                      const Standard_Boolean theIsInv,
842                      TopTools_DataMapOfShapeListOfShape& theEImages,
843                      TopoDS_Shape& theSplits);
844 
845   //! Updating the maps of images and origins of the offset edges
846   void UpdateNewIntersectionEdges (const TopTools_ListOfShape& theLE,
847                                    const TopTools_DataMapOfShapeListOfShape& theMELF,
848                                    const TopTools_DataMapOfShapeListOfShape& theEImages,
849                                    TopTools_DataMapOfShapeListOfShape& theEETrim);
850 
851 private:
852 
853   //! Fill possible gaps (holes) in the splits of the offset faces
854   void FillGaps (const Message_ProgressRange& theRange);
855 
856   //! Saving obtained results in history tools
857   void FillHistory();
858 
859 private:
860   // Input data
861   const TopTools_ListOfShape* myFaces;  //!< Input faces which have to be split
862   Handle(BRepAlgo_AsDes) myAsDes;       //!< Ascendants/descendants of the edges faces
863   const BRepOffset_Analyse* myAnalyzer; //!< Analyzer of the input parameters
864 
865   TopTools_DataMapOfShapeListOfShape* myEdgesOrigins; //!< Origins of the offset edges (binding between offset edge and original edge)
866   TopTools_DataMapOfShapeShape* myFacesOrigins;       //!< Origins of the offset faces (binding between offset face and original face)
867   TopTools_DataMapOfShapeShape* myETrimEInf;          //!< Binding between trimmed and infinite edge
868 
869   // Intermediate data
870   TopTools_DataMapOfShapeListOfShape myOEImages;        //!< Images of the offset edges
871   TopTools_DataMapOfShapeListOfShape myOEOrigins;       //!< Origins of the splits of offset edges
872   TopTools_IndexedDataMapOfShapeListOfShape myOFImages; //!< Images of the offset edges
873 
874   TopTools_IndexedMapOfShape myInvalidEdges;  //!< Edges considered invalid (orientation is changed) in some split of face
875   TopTools_IndexedMapOfShape myValidEdges;    //!< Edges considered valid (orientation is kept) in some split of face
876   TopTools_IndexedMapOfShape myInvertedEdges; //!< Edges considered inverted (vertices swapped) in some split of face
877   TopTools_IndexedMapOfShape myEdgesToAvoid;  //!< Splits of edges to be avoided when building splits of faces
878   TopTools_MapOfShape myLastInvEdges;         //!< Edges marked invalid on the current step and to be avoided on the next step
879   TopTools_MapOfShape myModifiedEdges;        //!< Edges to be used for building splits
880 
881   TopTools_IndexedDataMapOfShapeListOfShape myInvalidFaces; //!< Invalid faces - splits of offset faces consisting of invalid edges
882   TopTools_DataMapOfShapeShape myArtInvalidFaces;           //!< Artificially invalid faces - valid faces intentionally marked invalid
883                                                             //!  to be rebuilt on the future steps in the situations when invalid edges
884                                                             //!  are present, but invalid faces not
885   TopTools_DataMapOfShapeInteger myAlreadyInvFaces;         //!< Count number of the same face being marked invalid to avoid infinite
886                                                             //!  rebuilding of the same face
887   TopTools_DataMapOfShapeListOfShape myFNewHoles;           //!< Images of the hole faces of the original face
888 
889   TopTools_DataMapOfShapeListOfShape mySSInterfs; //!< Intersection information, used to collect intersection pairs during rebuild
890   NCollection_DataMap <TopoDS_Shape,
891     BRepOffset_DataMapOfShapeMapOfShape,
892     TopTools_ShapeMapHasher> myIntersectionPairs; //!< All possible intersection pairs, used to avoid some of the intersections
893 
894   TopTools_IndexedDataMapOfShapeListOfShape myFacesToRebuild; //!< Faces that have to be rebuilt (invalid and close to invalid faces)
895   TopTools_MapOfShape myFSelfRebAvoid;                        //!< Faces that have to be avoided when rebuilding splits of the same offset face
896 
897   TopoDS_Shape mySolids; //!< Solids built from the splits of faces
898 
899   // Auxiliary tools
900   Handle(IntTools_Context) myContext;
901 
902   // Output
903   BRepAlgo_Image* myImage;  //!< History of modifications
904 };
905 
906 //=======================================================================
907 //function : BuildSplitsOfTrimmedFaces
908 //purpose  :
909 //=======================================================================
BuildSplitsOfTrimmedFaces(const Message_ProgressRange & theRange)910 void BRepOffset_BuildOffsetFaces::BuildSplitsOfTrimmedFaces (const Message_ProgressRange& theRange)
911 {
912   if (!hasData (myFaces))
913   {
914     return;
915   }
916 
917   TopTools_DataMapOfShapeListOfShape anEdgesOrigins;
918   if (!myEdgesOrigins)
919   {
920     myEdgesOrigins = &anEdgesOrigins;
921   }
922 
923   Message_ProgressScope aPS (theRange, "Building splits of trimmed faces", 5);
924 
925   // Fuse all edges
926   IntersectTrimmedEdges (aPS.Next (1));
927 
928   Message_ProgressScope aPSLoop (aPS.Next (4), NULL, myFaces->Extent());
929   for (TopTools_ListOfShape::Iterator aItLF (*myFaces); aItLF.More(); aItLF.Next())
930   {
931     if (!aPSLoop.More())
932     {
933       return;
934     }
935     const TopoDS_Face& aF = *(TopoDS_Face*)&aItLF.Value();
936 
937     TopoDS_Shape aCE;
938     Standard_Boolean bFound = GetEdges (aF, aCE);
939 
940     // split the face by the edges
941     if (!bFound)
942     {
943       if (!myImage->HasImage (aF))
944       {
945         myOFImages (myOFImages.Add (aF, TopTools_ListOfShape())).Append (aF);
946       }
947       continue;
948     }
949 
950     TopTools_ListOfShape aLFImages;
951     BuildSplitsOfTrimmedFace (aF, aCE, aLFImages, aPSLoop.Next());
952 
953     myOFImages.Add (aF, aLFImages);
954   }
955   // Fill history for faces and edges
956   FillHistory();
957 }
958 
959 //=======================================================================
960 //function : BuildSplitsOfExtendedFaces
961 //purpose  :
962 //=======================================================================
BuildSplitsOfExtendedFaces(const Message_ProgressRange & theRange)963 void BRepOffset_BuildOffsetFaces::BuildSplitsOfExtendedFaces (const Message_ProgressRange& theRange)
964 {
965   // Check input data
966   if (!hasData (myFaces) || !hasData (myEdgesOrigins) || !hasData (myFacesOrigins) || !hasData (myETrimEInf))
967   {
968     return;
969   }
970 
971   Message_ProgressScope aPS (theRange, "Building splits of extended faces", 100.);
972   // Scope has to be added into a loop of undefined size.
973   // In general there are about 2 to 5 loops performed, each time
974   // decreasing complexity. So reserve for each next loop smaller time.
975   // Reserve also 4% on filling gaps after the faces are built.
976   Standard_Real aWhole = 100. - 4.;
977 
978   // Fusing all trimmed offset edges to avoid self-intersections in the splits
979   IntersectTrimmedEdges (aPS.Next());
980   if (!aPS.More())
981   {
982     return;
983   }
984   // vertices to avoid
985   TopTools_MapOfShape aVertsToAvoid;
986 
987   // Limit total number of attempts by 10. This should be extra, as each invalid face can be
988   // rebuilt only three times. So, in general, there are about 2-5 loops done.
989   const Standard_Integer aNbMaxAttempts = 10;
990   // First progress portion is the half of the whole. Each next step is half of the previous:
991   // 48%, 24%, 12%, 6% and so on. This way in three loops it will already be 84%,
992   // and in four - 90%. So even if the loop will stop earlier, the not advanced scope
993   // will be acceptable.
994   Standard_Real aPart = aWhole / 2.;
995   for (Standard_Integer iCount = 1; iCount <= aNbMaxAttempts; ++iCount, aPart /= 2.)
996   {
997     if (!aPS.More())
998     {
999       return;
1000     }
1001     // Clear the data before further faces construction
1002     myInvalidFaces.Clear();
1003     myArtInvalidFaces.Clear();
1004     myInvalidEdges.Clear();
1005     myInvertedEdges.Clear();
1006     mySSInterfs.Clear();
1007     myIntersectionPairs.Clear();
1008     mySolids.Nullify();
1009     myFacesToRebuild.Clear();
1010     myFSelfRebAvoid.Clear();
1011 
1012     // Split progress range on
1013     // * building faces basing on currently available edges and
1014     // * rebuilding faces basing on edges classification
1015     Message_ProgressScope aPSLoop (aPS.Next (aPart), NULL, 10.);
1016 
1017     // Build splits of the faces having new intersection edges
1018     BuildSplitsOfFaces (aPSLoop.Next (7.));
1019     if (myInvalidFaces.IsEmpty())
1020     {
1021       break;
1022     }
1023 
1024     // Find faces to rebuild
1025     FindFacesToRebuild();
1026     if (myFacesToRebuild.IsEmpty())
1027     {
1028       break;
1029     }
1030 
1031     // Perform new intersections
1032     myModifiedEdges.Clear();
1033     IntersectFaces (aVertsToAvoid, aPSLoop.Next (3.));
1034   }
1035 
1036   // Fill possible gaps in the splits of offset faces to increase possibility of
1037   // creating closed volume from these splits
1038   FillGaps (aPS.Next (4.));
1039 
1040   // Fill history for faces and edges
1041   FillHistory();
1042 }
1043 
1044 //=======================================================================
1045 //function : UpdateIntersectedEdges
1046 //purpose  : Saving connection from trimmed edges to not trimmed ones
1047 //=======================================================================
UpdateIntersectedEdges(const TopTools_ListOfShape & theLA,BOPAlgo_Builder & theGF)1048 void BRepOffset_BuildOffsetFaces::UpdateIntersectedEdges (const TopTools_ListOfShape& theLA,
1049                                                           BOPAlgo_Builder& theGF)
1050 {
1051   for (TopTools_ListOfShape::Iterator aItA (theLA); aItA.More(); aItA.Next())
1052   {
1053     const TopoDS_Shape& aS = aItA.Value();
1054     const TopoDS_Shape* pEInf = myETrimEInf->Seek (aS);
1055     if (!pEInf)
1056     {
1057       continue;
1058     }
1059 
1060     const TopTools_ListOfShape& aLSIm = theGF.Modified (aS);
1061     if (aLSIm.IsEmpty())
1062     {
1063       continue;
1064     }
1065 
1066     for (TopTools_ListOfShape::Iterator aIt (aLSIm); aIt.More(); aIt.Next())
1067     {
1068       const TopoDS_Shape& aEIm = aIt.Value();
1069       if (!myETrimEInf->IsBound (aEIm))
1070       {
1071         myETrimEInf->Bind (aEIm, *pEInf);
1072       }
1073     }
1074   }
1075 }
1076 
1077 //=======================================================================
1078 //function : IntersectTrimmedEdges
1079 //purpose  :
1080 //=======================================================================
IntersectTrimmedEdges(const Message_ProgressRange & theRange)1081 void BRepOffset_BuildOffsetFaces::IntersectTrimmedEdges (const Message_ProgressRange& theRange)
1082 {
1083   // get edges to intersect from descendants of the offset faces
1084   TopTools_ListOfShape aLS;
1085   //
1086   Message_ProgressScope aPS (theRange, NULL, 2);
1087   TopTools_ListIteratorOfListOfShape aItLF (*myFaces);
1088   for (; aItLF.More(); aItLF.Next())
1089   {
1090     if (!aPS.More())
1091     {
1092       return;
1093     }
1094     const TopoDS_Face& aF = *(TopoDS_Face*)&aItLF.Value();
1095     //
1096     const TopTools_ListOfShape& aLE = myAsDes->Descendant (aF);
1097     TopTools_ListIteratorOfListOfShape aItLE (aLE);
1098     for (; aItLE.More(); aItLE.Next())
1099     {
1100       const TopoDS_Edge& aE = *(TopoDS_Edge*)&aItLE.Value();
1101       //
1102       if (ProcessMicroEdge (aE, myContext))
1103       {
1104         continue;
1105       }
1106       //
1107       if (myModifiedEdges.Add (aE))
1108       {
1109         aLS.Append (aE);
1110       }
1111     }
1112   }
1113   //
1114   if (aLS.Extent() < 2)
1115   {
1116     // nothing to intersect
1117     return;
1118   }
1119   //
1120   // perform intersection of the edges
1121   BOPAlgo_Builder aGFE;
1122   aGFE.SetArguments (aLS);
1123   aGFE.Perform (aPS.Next());
1124   if (aGFE.HasErrors())
1125   {
1126     return;
1127   }
1128   //
1129   TopTools_ListOfShape aLA;
1130   // fill map with edges images
1131   Message_ProgressScope aPSLoop (aPS.Next(), NULL, aLS.Size());
1132   for (TopTools_ListOfShape::Iterator aIt (aLS); aIt.More(); aIt.Next(), aPSLoop.Next())
1133   {
1134     if (!aPSLoop.More())
1135     {
1136       return;
1137     }
1138     const TopoDS_Shape& aE = aIt.Value();
1139     const TopTools_ListOfShape& aLEIm = aGFE.Modified (aE);
1140     if (aLEIm.IsEmpty())
1141     {
1142       continue;
1143     }
1144     //
1145     aLA.Append (aE);
1146     // save images
1147     myOEImages.Bind (aE, aLEIm);
1148     // save origins
1149     TopTools_ListIteratorOfListOfShape aItLE (aLEIm);
1150     for (; aItLE.More(); aItLE.Next())
1151     {
1152       const TopoDS_Shape& aEIm = aItLE.Value();
1153       if (TopTools_ListOfShape* pLEOr = myOEOrigins.ChangeSeek (aEIm))
1154       {
1155         AppendToList (*pLEOr, aE);
1156       }
1157       else
1158       {
1159         myOEOrigins.Bound (aEIm, TopTools_ListOfShape())->Append (aE);
1160       }
1161     }
1162   }
1163   //
1164   UpdateOrigins (aLA, *myEdgesOrigins, aGFE);
1165   UpdateIntersectedEdges (aLA, aGFE);
1166 }
1167 
1168 //=======================================================================
1169 //function : BuildSplitsOfFaces
1170 //purpose  : Building the splits of offset faces and
1171 //           looking for the invalid splits
1172 //=======================================================================
BuildSplitsOfFaces(const Message_ProgressRange & theRange)1173 void BRepOffset_BuildOffsetFaces::BuildSplitsOfFaces (const Message_ProgressRange& theRange)
1174 {
1175   BRep_Builder aBB;
1176   Standard_Integer i, aNb;
1177   //
1178   // processed faces
1179   TopTools_ListOfShape aLFDone;
1180   // extended face - map of neutral edges, i.e. in one split - valid and in other - invalid
1181   BRepOffset_DataMapOfShapeMapOfShape aDMFMNE;
1182   // map of valid edges for each face
1183   BRepOffset_DataMapOfShapeMapOfShape aDMFMVE;
1184   // map of invalid edges for each face
1185   BRepOffset_DataMapOfShapeIndexedMapOfShape aDMFMIE;
1186   // map of valid inverted edges for the face
1187   BRepOffset_DataMapOfShapeMapOfShape aDMFMVIE;
1188   // map of splits to check for internals
1189   TopTools_IndexedMapOfShape aMFToCheckInt;
1190   // map of edges created from vertex and marked as invalid
1191   TopTools_MapOfShape aMEdgeInvalidByVertex;
1192   // map of edges created from vertex and marked as valid
1193   TopTools_MapOfShape aMEdgeValidByVertex;
1194   // connection map from old edges to new ones
1195   TopTools_DataMapOfShapeListOfShape aDMEOrLEIm;
1196   //
1197   // Outer range
1198   Message_ProgressScope aPSOuter (theRange, NULL, 10.);
1199   // build splits of faces
1200   Message_ProgressScope aPSBF (aPSOuter.Next (3.), "Building faces", 2 * myFaces->Extent());
1201   TopTools_ListOfShape::Iterator aItLF (*myFaces);
1202   for (; aItLF.More(); aItLF.Next(), aPSBF.Next())
1203   {
1204     if (!aPSBF.More())
1205     {
1206       return;
1207     }
1208     const TopoDS_Face& aF = *(TopoDS_Face*)&aItLF.Value();
1209     //
1210     TopTools_ListOfShape* pLFIm = myOFImages.ChangeSeek (aF);
1211     if (pLFIm && pLFIm->IsEmpty())
1212     {
1213       continue;
1214     }
1215     // get edges by which the face should be split
1216     TopoDS_Shape aCE;
1217     TopTools_IndexedMapOfShape aMapEInv;
1218     Standard_Boolean bFound = GetEdges (aF, aCE, &aMapEInv);
1219     if (!bFound)
1220     {
1221       continue;
1222     }
1223     //
1224 #ifdef OFFSET_DEBUG
1225     // check the found edges on self-intersection
1226     BRepAlgoAPI_Check aChecker (aCE);
1227     if (!aChecker.IsValid())
1228     {
1229       std::cout << "Offset_i_c Error: set of edges to build faces is self-intersecting\n";
1230     }
1231 #endif
1232     // build splits
1233     TopTools_ListOfShape aLFImages;
1234     BuildSplitsOfFace (aF, aCE, *myFacesOrigins, aLFImages);
1235     //
1236     if (aMapEInv.Extent())
1237     {
1238       // check if all possible faces are built
1239       TopTools_MapOfShape aMENInv;
1240       Standard_Boolean bArtificialCase = aLFImages.IsEmpty() ||
1241         CheckIfArtificial (aF, aLFImages, aCE, aMapEInv, aMENInv);
1242       //
1243       // try to build splits using invalid edges
1244       TopoDS_Compound aCE1;
1245       aBB.MakeCompound (aCE1);
1246       aBB.Add (aCE1, aCE);
1247       for (i = 1; i <= aMapEInv.Extent(); ++i)
1248       {
1249         aBB.Add (aCE1, aMapEInv (i));
1250       }
1251       //
1252       TopTools_ListOfShape aLFImages1;
1253       BuildSplitsOfFace (aF, aCE1, *myFacesOrigins, aLFImages1);
1254       //
1255       // check if the rebuilding has added some new faces to the splits
1256       for (TopTools_ListIteratorOfListOfShape aItLFIm (aLFImages1); aItLFIm.More();)
1257       {
1258         Standard_Boolean bAllInv = Standard_True;
1259         const TopoDS_Shape& aFIm = aItLFIm.Value();
1260         TopExp_Explorer aExpE (aFIm, TopAbs_EDGE);
1261         for (; aExpE.More(); aExpE.Next())
1262         {
1263           const TopoDS_Shape& aE = aExpE.Current();
1264           if (!aMapEInv.Contains (aE))
1265           {
1266             bAllInv = Standard_False;
1267             if (!aMENInv.Contains (aE))
1268             {
1269               break;
1270             }
1271           }
1272         }
1273         //
1274         if (!aExpE.More())
1275         {
1276           if (bAllInv)
1277           {
1278             aMFToCheckInt.Add (aFIm);
1279           }
1280           aLFImages1.Remove (aItLFIm);
1281         }
1282         else
1283         {
1284           aItLFIm.Next();
1285         }
1286       }
1287       //
1288       if (bArtificialCase)
1289       {
1290         if (aLFImages.Extent() == aLFImages1.Extent())
1291         {
1292           bArtificialCase = Standard_False;
1293         }
1294         else
1295         {
1296           aLFImages = aLFImages1;
1297         }
1298       }
1299       //
1300       if (bArtificialCase)
1301       {
1302         TopTools_IndexedMapOfShape aMEInv;
1303         // make the face invalid
1304         myArtInvalidFaces.Bind (aF, aCE);
1305         //
1306         *pLFIm = aLFImages;
1307         TopTools_ListIteratorOfListOfShape aItLFIm (aLFImages);
1308         for (; aItLFIm.More(); aItLFIm.Next())
1309         {
1310           const TopoDS_Shape& aFIm = aItLFIm.Value();
1311           TopExp_Explorer aExpE (aFIm, TopAbs_EDGE);
1312           for (; aExpE.More(); aExpE.Next())
1313           {
1314             const TopoDS_Shape& aE = aExpE.Current();
1315             if (aMapEInv.Contains (aE))
1316             {
1317               myInvalidEdges.Add (aE);
1318               aMEInv.Add (aE);
1319             }
1320             else
1321             {
1322               myValidEdges.Add (aE);
1323             }
1324           }
1325         }
1326         //
1327         aDMFMIE.Bind (aF, aMEInv);
1328         aLFDone.Append (aF);
1329         //
1330         continue;
1331       }
1332     }
1333 
1334     // find invalid edges
1335     FindInvalidEdges (aF, aLFImages, aDMFMVE, aDMFMNE, aDMFMIE, aDMFMVIE,
1336                       aDMEOrLEIm, aMEdgeInvalidByVertex, aMEdgeValidByVertex, aPSBF.Next());
1337 
1338     // save the new splits
1339     if (!pLFIm)
1340     {
1341       pLFIm = &myOFImages (myOFImages.Add (aF, TopTools_ListOfShape()));
1342     }
1343     else
1344     {
1345       pLFIm->Clear();
1346     }
1347     pLFIm->Append (aLFImages);
1348     //
1349     aLFDone.Append (aF);
1350   }
1351   //
1352   if (myInvalidEdges.IsEmpty() && myArtInvalidFaces.IsEmpty() && aDMFMIE.IsEmpty())
1353   {
1354     return;
1355   }
1356 
1357   // Additional step to find invalid edges by checking unclassified edges
1358   // in the splits of SD faces
1359   FindInvalidEdges (aLFDone, aDMFMIE, aDMFMVE, aDMFMNE);
1360 
1361   // Additional step to mark inverted edges located inside loops
1362   // of invalid edges as invalid as well
1363   MakeInvertedEdgesInvalid (aLFDone);
1364 
1365 #ifdef OFFSET_DEBUG
1366   // show invalid edges
1367   TopoDS_Compound aCEInv1;
1368   BRep_Builder().MakeCompound (aCEInv1);
1369   Standard_Integer aNbEInv = myInvalidEdges.Extent();
1370   for (i = 1; i <= aNbEInv; ++i)
1371   {
1372     const TopoDS_Shape& aE = myInvalidEdges (i);
1373     BRep_Builder().Add (aCEInv1, aE);
1374   }
1375   // show valid edges
1376   TopoDS_Compound aCEVal1;
1377   BRep_Builder().MakeCompound (aCEVal1);
1378   aNbEInv = myValidEdges.Extent();
1379   for (i = 1; i <= aNbEInv; ++i)
1380   {
1381     const TopoDS_Shape& aE = myValidEdges (i);
1382     BRep_Builder().Add (aCEVal1, aE);
1383   }
1384   // show inverted edges
1385   TopoDS_Compound aCEInverted;
1386   BRep_Builder().MakeCompound (aCEInverted);
1387   for (i = 1; i <= myInvertedEdges.Extent(); ++i)
1388   {
1389     BRep_Builder().Add (aCEInverted, myInvertedEdges(i));
1390   }
1391 #endif
1392 
1393 #ifdef OFFSET_DEBUG
1394   // Show all obtained splits of faces
1395   TopoDS_Compound aCFIm1;
1396   BRep_Builder().MakeCompound (aCFIm1);
1397 #endif
1398 
1399   // Build Edge-Face connectivity map to find faces which removal
1400   // may potentially lead to creation of the holes in the faces
1401   // preventing from obtaining closed volume in the result
1402   TopTools_IndexedDataMapOfShapeListOfShape anEFMap;
1403   const Standard_Integer aNbF = myOFImages.Extent();
1404   for (i = 1; i <= aNbF; ++i)
1405   {
1406     TopTools_ListIteratorOfListOfShape itLFIm (myOFImages (i));
1407     for (; itLFIm.More(); itLFIm.Next())
1408     {
1409       TopExp::MapShapesAndAncestors (itLFIm.Value(), TopAbs_EDGE, TopAbs_FACE, anEFMap);
1410 #ifdef OFFSET_DEBUG
1411       BRep_Builder().Add (aCFIm1, itLFIm.Value());
1412 #endif
1413     }
1414   }
1415 
1416   TopTools_MapOfShape anEmptyMap;
1417   // invalid faces inside the holes
1418   TopTools_IndexedMapOfShape aMFInvInHole;
1419   // all hole faces
1420   TopoDS_Compound aFHoles;
1421   aBB.MakeCompound (aFHoles);
1422   // Find the faces containing only the inverted edges and the invalid ones
1423   TopTools_ListOfShape anInvertedFaces;
1424 
1425   Message_ProgressScope aPSIF (aPSOuter.Next (2.), "Checking validity of faces", aLFDone.Extent());
1426   // find invalid faces
1427   // considering faces containing only invalid edges as invalid
1428   aItLF.Initialize (aLFDone);
1429   for (; aItLF.More(); aItLF.Next(), aPSIF.Next())
1430   {
1431     if (!aPSIF.More())
1432     {
1433       return;
1434     }
1435     const TopoDS_Face& aF = TopoDS::Face (aItLF.Value());
1436     TopTools_ListOfShape& aLFImages = myOFImages.ChangeFromKey (aF);
1437     //
1438     TopTools_ListOfShape aLFInv;
1439     Standard_Boolean bArtificialCase = myArtInvalidFaces.IsBound (aF);
1440     if (bArtificialCase)
1441     {
1442       aLFInv = aLFImages;
1443     }
1444     else
1445     {
1446       // neutral edges
1447       const TopTools_MapOfShape* pMNE = aDMFMNE.ChangeSeek (aF);
1448       if (!pMNE)
1449       {
1450         pMNE = &anEmptyMap;
1451       }
1452       // find faces inside holes wires
1453       TopTools_MapOfShape aMFHoles;
1454       const TopoDS_Face& aFOr = TopoDS::Face (myFacesOrigins->Find (aF));
1455       FindFacesInsideHoleWires (aFOr, aF, aLFImages, aDMEOrLEIm, anEFMap, aMFHoles);
1456       //
1457       TopTools_MapIteratorOfMapOfShape aItMH (aMFHoles);
1458       for (; aItMH.More(); aItMH.Next())
1459       {
1460         aBB.Add (aFHoles, aItMH.Value());
1461       }
1462       //
1463       // find invalid faces
1464       FindInvalidFaces (aLFImages, aDMFMVE, aDMFMIE, *pMNE, aMEdgeInvalidByVertex,
1465                         aMEdgeValidByVertex, aMFHoles, aMFInvInHole, aLFInv, anInvertedFaces);
1466     }
1467     //
1468     if (aLFInv.Extent())
1469     {
1470       if (myAlreadyInvFaces.IsBound (aF))
1471       {
1472         if (myAlreadyInvFaces.Find (aF) > 2)
1473         {
1474           if (aLFInv.Extent() == aLFImages.Extent() && !bArtificialCase)
1475           {
1476             aLFImages.Clear();
1477           }
1478           //
1479           aLFInv.Clear();
1480         }
1481       }
1482       myInvalidFaces.Add (aF, aLFInv);
1483     }
1484   }
1485   //
1486   if (myInvalidFaces.IsEmpty())
1487   {
1488     myInvalidEdges.Clear();
1489     return;
1490   }
1491   //
1492 #ifdef OFFSET_DEBUG
1493   // show invalid faces
1494   TopoDS_Compound aCFInv1;
1495   BRep_Builder().MakeCompound (aCFInv1);
1496   Standard_Integer aNbFInv = myInvalidFaces.Extent();
1497   for (i = 1; i <= aNbFInv; ++i)
1498   {
1499     const TopTools_ListOfShape& aLFInv = myInvalidFaces (i);
1500     TopTools_ListIteratorOfListOfShape aItLFInv (aLFInv);
1501     for (; aItLFInv.More(); aItLFInv.Next())
1502     {
1503       const TopoDS_Shape& aFIm = aItLFInv.Value();
1504       BRep_Builder().Add (aCFInv1, aFIm);
1505     }
1506   }
1507 #endif
1508   //
1509   TopTools_IndexedMapOfShape aMERemoved;
1510   // remove invalid splits of faces using inverted edges
1511   RemoveInvalidSplitsByInvertedEdges (aMERemoved);
1512   if (myInvalidFaces.IsEmpty())
1513   {
1514     myInvalidEdges.Clear();
1515     return;
1516   }
1517   //
1518   // remove invalid splits from valid splits
1519   RemoveInvalidSplitsFromValid (aDMFMVIE);
1520   //
1521   // remove inside faces
1522   TopTools_IndexedMapOfShape aMEInside;
1523   RemoveInsideFaces (anInvertedFaces, aMFToCheckInt, aMFInvInHole, aFHoles,
1524                      aMERemoved, aMEInside, aPSOuter.Next (5.));
1525   //
1526   // make compound of valid splits
1527   TopoDS_Compound aCFIm;
1528   aBB.MakeCompound (aCFIm);
1529   //
1530   aNb = myOFImages.Extent();
1531   for (i = 1; i <= aNb; ++i)
1532   {
1533     const TopTools_ListOfShape& aLFIm = myOFImages (i);
1534     aItLF.Initialize (aLFIm);
1535     for (; aItLF.More(); aItLF.Next())
1536     {
1537       const TopoDS_Shape& aFIm = aItLF.Value();
1538       aBB.Add (aCFIm, aFIm);
1539     }
1540   }
1541   //
1542   TopTools_IndexedDataMapOfShapeListOfShape aDMEF;
1543   TopExp::MapShapesAndAncestors (aCFIm, TopAbs_EDGE, TopAbs_FACE, aDMEF);
1544   //
1545   // filter maps of images and origins
1546   FilterEdgesImages (aCFIm);
1547   //
1548   // filter invalid faces
1549   FilterInvalidFaces (aDMEF, aMEInside);
1550   aNb = myInvalidFaces.Extent();
1551   if (!aNb)
1552   {
1553     myInvalidEdges.Clear();
1554     return;
1555   }
1556   //
1557 #ifdef OFFSET_DEBUG
1558   // show invalid faces
1559   TopoDS_Compound aCFInv;
1560   BRep_Builder().MakeCompound (aCFInv);
1561   aNbFInv = myInvalidFaces.Extent();
1562   for (i = 1; i <= aNbFInv; ++i)
1563   {
1564     const TopTools_ListOfShape& aLFInv = myInvalidFaces (i);
1565     TopTools_ListIteratorOfListOfShape aItLFInv (aLFInv);
1566     for (; aItLFInv.More(); aItLFInv.Next())
1567     {
1568       const TopoDS_Shape& aFIm = aItLFInv.Value();
1569       BRep_Builder().Add (aCFInv, aFIm);
1570     }
1571   }
1572 #endif
1573   //
1574   // filter invalid edges
1575   FilterInvalidEdges (aDMFMIE, aMERemoved);
1576   //
1577   // Check additionally validity of edges originated from vertices.
1578   CheckEdgesCreatedByVertex();
1579 
1580 #ifdef OFFSET_DEBUG
1581   // show invalid edges
1582   TopoDS_Compound aCEInv;
1583   BRep_Builder().MakeCompound (aCEInv);
1584   aNbEInv = myInvalidEdges.Extent();
1585   for (i = 1; i <= aNbEInv; ++i)
1586   {
1587     const TopoDS_Shape& aE = myInvalidEdges (i);
1588     BRep_Builder().Add (aCEInv, aE);
1589   }
1590 #endif
1591   //
1592   myLastInvEdges.Clear();
1593   aNb = myInvalidEdges.Extent();
1594   for (i = 1; i <= aNb; ++i)
1595   {
1596     const TopoDS_Shape& aE = myInvalidEdges (i);
1597     myEdgesToAvoid.Add (aE);
1598     myLastInvEdges.Add (aE);
1599   }
1600   //
1601   aNb = myInvalidFaces.Extent();
1602   for (i = 1; i <= aNb; ++i)
1603   {
1604     const TopoDS_Shape& aF = myInvalidFaces.FindKey (i);
1605     if (myAlreadyInvFaces.IsBound (aF))
1606     {
1607       myAlreadyInvFaces.ChangeFind (aF)++;
1608     }
1609     else
1610     {
1611       myAlreadyInvFaces.Bind (aF, 1);
1612     }
1613   }
1614 }
1615 
1616 //=======================================================================
1617 //function : GetEdges
1618 //purpose  : Getting edges from AsDes map to build the splits of faces
1619 //=======================================================================
GetEdges(const TopoDS_Face & theFace,TopoDS_Shape & theEdges,TopTools_IndexedMapOfShape * theInvMap)1620 Standard_Boolean BRepOffset_BuildOffsetFaces::GetEdges (const TopoDS_Face& theFace,
1621                                                         TopoDS_Shape& theEdges,
1622                                                         TopTools_IndexedMapOfShape* theInvMap)
1623 {
1624   // get boundary edges
1625   TopTools_MapOfShape aMFBounds;
1626   TopExp_Explorer aExp (theFace, TopAbs_EDGE);
1627   for (; aExp.More(); aExp.Next())
1628   {
1629     const TopoDS_Shape& aE = aExp.Current();
1630     if (const TopTools_ListOfShape* pLEIm = myOEImages.Seek (aE))
1631     {
1632       for (TopTools_ListOfShape::Iterator aItLE (*pLEIm); aItLE.More(); aItLE.Next())
1633       {
1634         aMFBounds.Add (aItLE.Value());
1635       }
1636     }
1637     else
1638     {
1639       aMFBounds.Add (aE);
1640     }
1641   }
1642 
1643   BRep_Builder aBB;
1644   Standard_Boolean bFound (Standard_False), bUpdate (Standard_False);
1645   // the resulting edges
1646   TopoDS_Compound anEdges;
1647   aBB.MakeCompound (anEdges);
1648   // Fence map
1649   TopTools_MapOfShape aMEFence;
1650   // the edges by which the offset face should be split
1651   const TopTools_ListOfShape& aLE = myAsDes->Descendant (theFace);
1652   TopTools_ListIteratorOfListOfShape aItLE (aLE);
1653   for (; aItLE.More(); aItLE.Next())
1654   {
1655     const TopoDS_Edge& aE = TopoDS::Edge (aItLE.Value());
1656     //
1657     if (!bUpdate)
1658     {
1659       bUpdate = myModifiedEdges.Contains (aE);
1660     }
1661     //
1662     const TopTools_ListOfShape* pLEIm = myOEImages.Seek (aE);
1663     if (pLEIm)
1664     {
1665       TopTools_ListIteratorOfListOfShape aItLEIm (*pLEIm);
1666       for (; aItLEIm.More(); aItLEIm.Next())
1667       {
1668         const TopoDS_Edge& aEIm = TopoDS::Edge (aItLEIm.Value());
1669         //
1670         if (!aMEFence.Add (aEIm))
1671           continue;
1672 
1673         if (myEdgesToAvoid.Contains (aEIm))
1674         {
1675           if (theInvMap)
1676           {
1677             theInvMap->Add (aEIm);
1678           }
1679           if (!bUpdate)
1680           {
1681             bUpdate = myLastInvEdges.Contains (aEIm);
1682           }
1683           continue;
1684         }
1685         // check for micro edge
1686         if (ProcessMicroEdge (aEIm, myContext))
1687         {
1688           continue;
1689         }
1690         //
1691         aBB.Add (anEdges, aEIm);
1692         if (!bFound)
1693         {
1694           bFound = !aMFBounds.Contains (aEIm);
1695         }
1696         //
1697         if (!bUpdate)
1698         {
1699           bUpdate = myModifiedEdges.Contains (aEIm);
1700         }
1701       }
1702     }
1703     else
1704     {
1705       if (myEdgesToAvoid.Contains (aE))
1706       {
1707         if (theInvMap)
1708         {
1709           theInvMap->Add (aE);
1710         }
1711         if (!bUpdate)
1712         {
1713           bUpdate = myLastInvEdges.Contains (aE);
1714         }
1715         continue;
1716       }
1717       //
1718       if (ProcessMicroEdge (aE, myContext))
1719       {
1720         continue;
1721       }
1722       aBB.Add (anEdges, aE);
1723       if (!bFound)
1724       {
1725         bFound = !aMFBounds.Contains (aE);
1726       }
1727     }
1728   }
1729   //
1730   theEdges = anEdges;
1731   return bFound && bUpdate;
1732 }
1733 
1734 
1735 //=======================================================================
1736 //function : CheckIfArtificial
1737 //purpose  : Checks if the face is artificially invalid
1738 //=======================================================================
CheckIfArtificial(const TopoDS_Shape & theF,const TopTools_ListOfShape & theLFImages,const TopoDS_Shape & theCE,const TopTools_IndexedMapOfShape & theMapEInv,TopTools_MapOfShape & theMENInv)1739 Standard_Boolean BRepOffset_BuildOffsetFaces::CheckIfArtificial (const TopoDS_Shape& theF,
1740                                                                  const TopTools_ListOfShape& theLFImages,
1741                                                                  const TopoDS_Shape& theCE,
1742                                                                  const TopTools_IndexedMapOfShape& theMapEInv,
1743                                                                  TopTools_MapOfShape& theMENInv)
1744 {
1745   // all boundary edges should be used
1746   TopTools_IndexedMapOfShape aMEUsed;
1747   TopTools_ListIteratorOfListOfShape aItLFIm (theLFImages);
1748   for (; aItLFIm.More(); aItLFIm.Next())
1749   {
1750     const TopoDS_Shape& aFIm = aItLFIm.Value();
1751     TopExp::MapShapes (aFIm, TopAbs_EDGE, aMEUsed);
1752     TopExp::MapShapes (aFIm, TopAbs_VERTEX, aMEUsed);
1753   }
1754   //
1755   TopTools_IndexedDataMapOfShapeListOfShape aMVE;
1756   TopExp::MapShapesAndAncestors (theCE, TopAbs_VERTEX, TopAbs_EDGE, aMVE);
1757   //
1758   Standard_Integer i, aNb = theMapEInv.Extent();
1759   for (i = 1; i <= aNb; ++i)
1760   {
1761     const TopoDS_Shape& aEInv = theMapEInv (i);
1762     TopExp_Explorer aExpV (aEInv, TopAbs_VERTEX);
1763     for (; aExpV.More(); aExpV.Next())
1764     {
1765       const TopoDS_Shape& aVEInv = aExpV.Current();
1766       const TopTools_ListOfShape* pLENInv = aMVE.Seek (aVEInv);
1767       if (pLENInv)
1768       {
1769         TopTools_ListIteratorOfListOfShape aItLEInv (*pLENInv);
1770         for (; aItLEInv.More(); aItLEInv.Next())
1771         {
1772           const TopoDS_Shape& aENInv = aItLEInv.Value();
1773           if (!aMEUsed.Contains (aENInv))
1774           {
1775             theMENInv.Add (aENInv);
1776           }
1777         }
1778       }
1779     }
1780   }
1781   //
1782   if (theMENInv.IsEmpty())
1783   {
1784     return Standard_False;
1785   }
1786   //
1787   TopTools_IndexedMapOfShape aMEFound;
1788   TopExp::MapShapes (theCE, TopAbs_EDGE, aMEFound);
1789   //
1790   const TopTools_ListOfShape& aLE = myAsDes->Descendant (theF);
1791   TopTools_ListIteratorOfListOfShape aItLE (aLE);
1792   for (; aItLE.More(); aItLE.Next())
1793   {
1794     const TopoDS_Edge& aE = TopoDS::Edge (aItLE.Value());
1795     //
1796     if (myOEImages.IsBound (aE))
1797     {
1798       Standard_Boolean bChecked = Standard_False;
1799       const TopTools_ListOfShape& aLEIm = myOEImages.Find (aE);
1800       TopTools_ListIteratorOfListOfShape aItLEIm (aLEIm);
1801       for (; aItLEIm.More(); aItLEIm.Next())
1802       {
1803         const TopoDS_Edge& aEIm = TopoDS::Edge (aItLEIm.Value());
1804         if (!aMEFound.Contains (aEIm) || theMENInv.Contains (aEIm))
1805         {
1806           continue;
1807         }
1808         //
1809         bChecked = Standard_True;
1810         if (aMEUsed.Contains (aEIm))
1811         {
1812           break;
1813         }
1814       }
1815       //
1816       if (bChecked && !aItLEIm.More())
1817       {
1818         break;
1819       }
1820     }
1821     else
1822     {
1823       if (aMEFound.Contains (aE) && !theMENInv.Contains (aE) && !aMEUsed.Contains (aE))
1824       {
1825         break;
1826       }
1827     }
1828   }
1829   //
1830   return aItLE.More();
1831 }
1832 
1833 //=======================================================================
1834 //function : FindInvalidEdges
1835 //purpose  : Looking for the invalid edges
1836 //=======================================================================
FindInvalidEdges(const TopoDS_Face & theF,const TopTools_ListOfShape & theLFImages,BRepOffset_DataMapOfShapeMapOfShape & theDMFMVE,BRepOffset_DataMapOfShapeMapOfShape & theDMFMNE,BRepOffset_DataMapOfShapeIndexedMapOfShape & theDMFMIE,BRepOffset_DataMapOfShapeMapOfShape & theDMFMVIE,TopTools_DataMapOfShapeListOfShape & theDMEOrLEIm,TopTools_MapOfShape & theEdgesInvalidByVertex,TopTools_MapOfShape & theEdgesValidByVertex,const Message_ProgressRange & theRange)1837 void BRepOffset_BuildOffsetFaces::FindInvalidEdges (const TopoDS_Face& theF,
1838                                                     const TopTools_ListOfShape& theLFImages,
1839                                                     BRepOffset_DataMapOfShapeMapOfShape& theDMFMVE,
1840                                                     BRepOffset_DataMapOfShapeMapOfShape& theDMFMNE,
1841                                                     BRepOffset_DataMapOfShapeIndexedMapOfShape& theDMFMIE,
1842                                                     BRepOffset_DataMapOfShapeMapOfShape& theDMFMVIE,
1843                                                     TopTools_DataMapOfShapeListOfShape& theDMEOrLEIm,
1844                                                     TopTools_MapOfShape& theEdgesInvalidByVertex,
1845                                                     TopTools_MapOfShape& theEdgesValidByVertex,
1846                                                     const Message_ProgressRange& theRange)
1847 {
1848   // Edge is considered as invalid in the following cases:
1849   // 1. Its orientation on the face has changed comparing to the originals edge and face;
1850   // 2. The vertices of the edge have changed places comparing to the originals edge and face.
1851   //
1852   // The edges created from vertices, i.e. as intersection between two faces connected only
1853   // by VERTEX, will also be checked on validity. For these edges the correct orientation will
1854   // be defined by the edges on the original face adjacent to the connection vertex
1855 
1856   // original face
1857   const TopoDS_Face& aFOr = *(TopoDS_Face*)&myFacesOrigins->Find (theF);
1858   // invalid edges
1859   TopTools_IndexedMapOfShape aMEInv;
1860   // valid edges
1861   TopTools_MapOfShape aMEVal;
1862   // internal edges
1863   TopTools_MapOfShape aMEInt;
1864   //
1865   // maps for checking the inverted edges
1866   TopTools_IndexedDataMapOfShapeListOfShape aDMVE, aDMEF;
1867   TopTools_IndexedMapOfShape aMEdges;
1868   // back map from the original shapes to their offset images
1869   TopTools_DataMapOfShapeListOfShape anImages;
1870   //
1871   Message_ProgressScope aPS (theRange, "Checking validity of edges", 2 * theLFImages.Extent());
1872   TopTools_ListIteratorOfListOfShape aItLF (theLFImages);
1873   for (; aItLF.More(); aItLF.Next(), aPS.Next())
1874   {
1875     if (!aPS.More())
1876     {
1877       return;
1878     }
1879     const TopoDS_Face& aFIm = *(TopoDS_Face*)&aItLF.Value();
1880     //
1881     TopExp_Explorer aExp (aFIm, TopAbs_EDGE);
1882     for (; aExp.More(); aExp.Next())
1883     {
1884       const TopoDS_Shape& aE = aExp.Current();
1885       // keep all edges
1886       aMEdges.Add (aE);
1887       //
1888       // keep connection from edges to faces
1889       TopTools_ListOfShape* pLF = aDMEF.ChangeSeek (aE);
1890       if (!pLF)
1891       {
1892         pLF = &aDMEF (aDMEF.Add (aE, TopTools_ListOfShape()));
1893       }
1894       AppendToList (*pLF, aFIm);
1895       //
1896       // keep connection from vertices to edges
1897       TopoDS_Iterator aItV (aE);
1898       for (; aItV.More(); aItV.Next())
1899       {
1900         const TopoDS_Shape& aV = aItV.Value();
1901         //
1902         TopTools_ListOfShape* pLE = aDMVE.ChangeSeek (aV);
1903         if (!pLE)
1904         {
1905           pLE = &aDMVE (aDMVE.Add (aV, TopTools_ListOfShape()));
1906         }
1907         AppendToList (*pLE, aE);
1908       }
1909 
1910       // back map from original edges to their offset images
1911       const TopTools_ListOfShape* pLOr = myEdgesOrigins->Seek (aE);
1912       if (!pLOr)
1913         continue;
1914       for (TopTools_ListOfShape::Iterator itOr (*pLOr); itOr.More(); itOr.Next())
1915       {
1916         const TopoDS_Shape& aSOr = itOr.Value();
1917         TopoDS_Shape aSInF;
1918         if (!FindShape (aSOr, aFOr, myAnalyzer, aSInF))
1919           continue;
1920         TopTools_ListOfShape* pImages = anImages.ChangeSeek (aSInF);
1921         if (!pImages)
1922           pImages = anImages.Bound (aSInF, TopTools_ListOfShape());
1923         AppendToList (*pImages, aE);
1924       }
1925     }
1926   }
1927   //
1928   // the map will be used to find the edges on the original face
1929   // adjacent to the same vertex. It will be filled at first necessity;
1930   TopTools_IndexedDataMapOfShapeListOfShape aDMVEFOr;
1931   //
1932   aItLF.Initialize (theLFImages);
1933   for (; aItLF.More(); aItLF.Next(), aPS.Next())
1934   {
1935     if (!aPS.More())
1936     {
1937       return;
1938     }
1939     const TopoDS_Face& aFIm = *(TopoDS_Face*)&aItLF.Value();
1940     //
1941     // valid edges for this split
1942     TopTools_MapOfShape aMVE;
1943     // invalid edges for this split
1944     TopTools_IndexedMapOfShape aMIE;
1945     //
1946     TopExp_Explorer aExp (aFIm, TopAbs_EDGE);
1947     for (; aExp.More(); aExp.Next())
1948     {
1949       const TopoDS_Edge& aEIm = *(TopoDS_Edge*)&aExp.Current();
1950       //
1951       if (aEIm.Orientation() == TopAbs_INTERNAL)
1952       {
1953         aMEInt.Add (aEIm);
1954         continue;
1955       }
1956       //
1957       const TopTools_ListOfShape* pLEOr = myEdgesOrigins->Seek (aEIm);
1958       if (!pLEOr || pLEOr->IsEmpty())
1959       {
1960         continue;
1961       }
1962       //
1963       Standard_Integer aNbVOr = 0;
1964       TopTools_ListIteratorOfListOfShape aItLEO (*pLEOr);
1965       for (; aItLEO.More(); aItLEO.Next())
1966       {
1967         if (aItLEO.Value().ShapeType() == TopAbs_VERTEX)
1968         {
1969           ++aNbVOr;
1970         }
1971       }
1972       if (aNbVOr > 1 && (pLEOr->Extent() - aNbVOr) > 1)
1973         continue;
1974       //
1975       TopTools_MapOfShape aME, aMV, aMF;
1976       Standard_Boolean bInvalid = Standard_False, bChecked = Standard_False;
1977       Standard_Integer aNbP = NbPoints (aEIm), aNbInv = 0;
1978       Standard_Boolean bUseVertex = !aNbVOr ? Standard_False :
1979         (aNbVOr == 1 &&
1980          aDMEF.FindFromKey (aEIm).Extent() == 1 &&
1981          !myOEOrigins.IsBound (aEIm));
1982       //
1983       aItLEO.Initialize (*pLEOr);
1984       for (; aItLEO.More(); aItLEO.Next())
1985       {
1986         const TopoDS_Shape& aSOr = aItLEO.Value();
1987         Standard_Boolean bVertex = (aSOr.ShapeType() == TopAbs_VERTEX);
1988         //
1989         TopoDS_Shape aEOrF;
1990         if (bVertex)
1991         {
1992           // for some cases it is impossible to check the validity of the edge
1993           if (!bUseVertex)
1994           {
1995             continue;
1996           }
1997           // find edges on the original face adjacent to this vertex
1998           if (aDMVEFOr.IsEmpty())
1999           {
2000             // fill the map
2001             TopExp::MapShapesAndAncestors (aFOr, TopAbs_VERTEX, TopAbs_EDGE, aDMVEFOr);
2002           }
2003           //
2004           TopTools_ListOfShape* pLEFOr = aDMVEFOr.ChangeSeek (aSOr);
2005           if (pLEFOr)
2006           {
2007             TopoDS_Compound aCEOr;
2008             BRep_Builder().MakeCompound (aCEOr);
2009             // Avoid classification of edges originated from vertices
2010             // located between tangent edges
2011             Standard_Boolean bAllTgt = Standard_True;
2012             TopTools_ListIteratorOfListOfShape aItLEFOr (*pLEFOr);
2013             gp_Vec aVRef = GetAverageTangent (aItLEFOr.Value(), aNbP);
2014             for (; aItLEFOr.More(); aItLEFOr.Next())
2015             {
2016               const TopoDS_Shape& aEOr = aItLEFOr.Value();
2017               BRep_Builder().Add (aCEOr, aEOr);
2018 
2019               gp_Vec aVCur = GetAverageTangent (aEOr, aNbP);
2020               if (!aVRef.IsParallel (aVCur, Precision::Angular()))
2021                 bAllTgt = Standard_False;
2022             }
2023             if (!bAllTgt)
2024               aEOrF = aCEOr;
2025           }
2026         }
2027         else
2028         {
2029           FindShape (aSOr, aFOr, myAnalyzer, aEOrF);
2030           //
2031           TopTools_ListOfShape* pLEIm = theDMEOrLEIm.ChangeSeek (aSOr);
2032           if (!pLEIm)
2033           {
2034             pLEIm = theDMEOrLEIm.Bound (aSOr, TopTools_ListOfShape());
2035           }
2036           AppendToList (*pLEIm, aEIm);
2037         }
2038         //
2039         if (aEOrF.IsNull())
2040         {
2041           // the edge has not been found
2042           continue;
2043         }
2044 
2045         if (bVertex)
2046         {
2047           TopTools_MapOfShape aMVTotal;
2048           Standard_Integer aNbChecked = 0;
2049           // Just check if the original edges sharing the vertex do not share it any more.
2050           for (TopoDS_Iterator it (aEOrF); it.More(); it.Next())
2051           {
2052             const TopoDS_Shape& aEOr = it.Value();
2053             const TopTools_ListOfShape* aLIm = anImages.Seek (aEOr);
2054             if (!aLIm)
2055               continue;
2056             ++aNbChecked;
2057             TopTools_IndexedDataMapOfShapeListOfShape aMVLoc;
2058             for (TopTools_ListOfShape::Iterator itLIM (*aLIm); itLIM.More(); itLIM.Next())
2059               TopExp::MapShapesAndAncestors (itLIM.Value(), TopAbs_VERTEX, TopAbs_EDGE, aMVLoc);
2060             for (Standard_Integer i = 1; i <= aMVLoc.Extent(); ++i)
2061             {
2062               if (aMVLoc (i).Extent() > 1 && !aMVTotal.Add (aMVLoc.FindKey (i)))
2063               {
2064                 bInvalid = Standard_True;
2065                 theEdgesInvalidByVertex.Add (aEIm);
2066                 break;
2067               }
2068             }
2069             if (bInvalid)
2070               break;
2071           }
2072           if (!bInvalid && aNbChecked < 2)
2073             continue;
2074           else
2075             theEdgesValidByVertex.Add (aEIm);
2076         }
2077         else
2078         {
2079           //
2080           // Check orientations of the image edge and original edge.
2081           // In case the 3d curves are having the same direction the orientations
2082           // must be the same. Otherwise the orientations should also be different.
2083           //
2084           // get average tangent vector for each curve taking into account
2085           // the orientations of the edges, i.e. the edge is reversed
2086           // the vector is reversed as well
2087           gp_Vec aVSum1 = GetAverageTangent (aEIm, aNbP);
2088           gp_Vec aVSum2 = GetAverageTangent (aEOrF, aNbP);
2089           //
2090           aVSum1.Normalize();
2091           aVSum2.Normalize();
2092           //
2093           Standard_Real aCos = aVSum1.Dot (aVSum2);
2094           if (Abs (aCos) < 0.9999)
2095           {
2096             continue;
2097           }
2098           //
2099           aME.Add (aEOrF);
2100           TopExp_Explorer aExpE (aEOrF, TopAbs_VERTEX);
2101           for (; aExpE.More(); aExpE.Next())
2102           {
2103             const TopoDS_Shape& aV = aExpE.Current();
2104             aMV.Add (aV);
2105           }
2106           if (myAnalyzer)
2107           {
2108             for (TopTools_ListOfShape::Iterator itFA (myAnalyzer->Ancestors (aEOrF));
2109                  itFA.More(); itFA.Next())
2110               aMF.Add (itFA.Value());
2111           }
2112           //
2113           if (aCos < Precision::Confusion())
2114           {
2115             bInvalid = Standard_True;
2116             aNbInv++;
2117           }
2118         }
2119         bChecked = Standard_True;
2120       }
2121       //
2122       if (!bChecked)
2123       {
2124         continue;
2125       }
2126       //
2127       Standard_Boolean bLocalOnly = (aNbVOr > 1 && (pLEOr->Extent() - aNbVOr) > 1);
2128       Standard_Integer aNbE = aME.Extent(), aNbV = aMV.Extent();
2129       if (aNbE > 1 && aNbV == 2 * aNbE)
2130       {
2131         Standard_Boolean bSkip = Standard_True;
2132 
2133         // It seems the edge originated from not connected edges and cannot be
2134         // considered as correctly classified as it may fill some undesired parts.
2135         // Still, allow the edge to be accounted for local analysis if it is:
2136         // * originated from more than two faces
2137         // * unanimously considered valid or invalid
2138         // * not a boundary edge in the splits
2139         if (aMF.Extent() > 2 && (aNbInv == 0 || aNbInv == aNbE))
2140         {
2141           if (theLFImages.Extent() > 2)
2142           {
2143             TopoDS_Iterator itV (aEIm);
2144             for (; itV.More(); itV.Next())
2145             {
2146               TopTools_ListOfShape::Iterator itE (aDMVE.FindFromKey (itV.Value()));
2147               for (; itE.More(); itE.Next())
2148                 if (aDMEF.FindFromKey (itE.Value()).Extent() < 2)
2149                   break;
2150               if (itE.More())
2151                 break;
2152             }
2153             bSkip = itV.More();
2154           }
2155         }
2156         if (bSkip)
2157           continue;
2158         else
2159           bLocalOnly = Standard_True;
2160       }
2161       //
2162       if (bInvalid)
2163       {
2164         if (!bLocalOnly)
2165           myInvalidEdges.Add (aEIm);
2166         aMIE.Add (aEIm);
2167         aMEInv.Add (aEIm);
2168         continue;
2169       }
2170       //
2171       // check if the edge has been inverted
2172       Standard_Boolean bInverted = !aNbE || bLocalOnly ? Standard_False :
2173         CheckInverted (aEIm, aFOr, aDMVE, aMEdges);
2174       //
2175       if (!bInverted || !aNbVOr)
2176       {
2177         if (!bLocalOnly)
2178           myValidEdges.Add (aEIm);
2179         aMVE.Add (aEIm);
2180         aMEVal.Add (aEIm);
2181       }
2182     }
2183     //
2184     // valid edges
2185     if (aMVE.Extent())
2186     {
2187       theDMFMVE.Bind (aFIm, aMVE);
2188     }
2189     //
2190     // invalid edges
2191     if (aMIE.Extent())
2192     {
2193       theDMFMIE.Bind (aFIm, aMIE);
2194     }
2195   }
2196   //
2197   // process invalid edges:
2198   // check for the inverted edges
2199   TopTools_MapOfShape aMVIE;
2200   // fill neutral edges
2201   TopTools_MapOfShape aMNE;
2202   //
2203   Standard_Integer i, aNbEInv = aMEInv.Extent();
2204   for (i = 1; i <= aNbEInv; ++i)
2205   {
2206     const TopoDS_Shape& aEIm = aMEInv (i);
2207     //
2208     // neutral edges - on the splits of the same offset face
2209     // it is valid for one split and invalid for other
2210     if (aMEVal.Contains (aEIm))
2211     {
2212       aMNE.Add (aEIm);
2213       continue;
2214     }
2215     //
2216     // the inverted images of the origins of invalid edges should also be invalid
2217     if (!myInvertedEdges.Contains (aEIm))
2218     {
2219       continue;
2220     }
2221     //
2222     const TopTools_ListOfShape* pLOEOr = myOEOrigins.Seek (aEIm);
2223     if (!pLOEOr)
2224     {
2225       continue;
2226     }
2227     //
2228     TopTools_ListIteratorOfListOfShape aItLOEOr (*pLOEOr);
2229     for (; aItLOEOr.More(); aItLOEOr.Next())
2230     {
2231       const TopoDS_Shape& aOEOr = aItLOEOr.Value();
2232       const TopTools_ListOfShape& aLEIm1 = myOEImages.Find (aOEOr);
2233       //
2234       TopTools_ListIteratorOfListOfShape aItLEIm1 (aLEIm1);
2235       for (; aItLEIm1.More(); aItLEIm1.Next())
2236       {
2237         const TopoDS_Shape& aEIm1 = aItLEIm1.Value();
2238         if (aMEdges.Contains (aEIm1) &&
2239             !aMEInv.Contains (aEIm1) && !aMEInt.Contains (aEIm1) &&
2240             myInvertedEdges.Contains (aEIm1))
2241         {
2242           myInvalidEdges.Add (aEIm1);
2243           aMVIE.Add (aEIm1);
2244         }
2245       }
2246     }
2247   }
2248   //
2249   if (aMNE.Extent())
2250   {
2251     theDMFMNE.Bind (theF, aMNE);
2252   }
2253   //
2254   if (aMVIE.Extent())
2255   {
2256     theDMFMVIE.Bind (theF, aMVIE);
2257   }
2258 }
2259 
2260 namespace {
2261   //=======================================================================
2262   //function : addAsNeutral
2263   //purpose  : Adds as the edge into corresponding maps making it neutral
2264   //=======================================================================
addAsNeutral(const TopoDS_Shape & theE,const TopoDS_Shape & theFInv,const TopoDS_Shape & theFVal,BRepOffset_DataMapOfShapeIndexedMapOfShape & theLocInvEdges,BRepOffset_DataMapOfShapeMapOfShape & theLocValidEdges)2265   static void addAsNeutral (const TopoDS_Shape& theE,
2266                             const TopoDS_Shape& theFInv,
2267                             const TopoDS_Shape& theFVal,
2268                             BRepOffset_DataMapOfShapeIndexedMapOfShape& theLocInvEdges,
2269                             BRepOffset_DataMapOfShapeMapOfShape& theLocValidEdges)
2270   {
2271     TopTools_IndexedMapOfShape* pMEInv = theLocInvEdges.ChangeSeek (theFInv);
2272     if (!pMEInv)
2273       pMEInv = theLocInvEdges.Bound (theFInv, TopTools_IndexedMapOfShape());
2274     pMEInv->Add (theE);
2275 
2276     TopTools_MapOfShape* pMEVal = theLocValidEdges.ChangeSeek (theFVal);
2277     if (!pMEVal)
2278       pMEVal = theLocValidEdges.Bound (theFVal, TopTools_MapOfShape());
2279     pMEVal->Add (theE);
2280   }
2281 
2282 }
2283 //=======================================================================
2284 //function : FindInvalidEdges
2285 //purpose  : Additional method to look for invalid edges
2286 //=======================================================================
FindInvalidEdges(const TopTools_ListOfShape & theLFOffset,BRepOffset_DataMapOfShapeIndexedMapOfShape & theLocInvEdges,BRepOffset_DataMapOfShapeMapOfShape & theLocValidEdges,BRepOffset_DataMapOfShapeMapOfShape & theNeutralEdges)2287 void BRepOffset_BuildOffsetFaces::FindInvalidEdges (const TopTools_ListOfShape& theLFOffset,
2288                                                     BRepOffset_DataMapOfShapeIndexedMapOfShape& theLocInvEdges,
2289                                                     BRepOffset_DataMapOfShapeMapOfShape& theLocValidEdges,
2290                                                     BRepOffset_DataMapOfShapeMapOfShape& theNeutralEdges)
2291 {
2292   // 1. Find edges unclassified in faces
2293   // 2. Find SD faces in which the same edge is classified
2294   // 3. Check if the edge is neutral in face in which it wasn't classified
2295 
2296   NCollection_IndexedDataMap<TopoDS_Shape, TopTools_MapOfShape, TopTools_ShapeMapHasher> aMEUnclassified;
2297   TopTools_DataMapOfShapeShape aFSplitFOffset;
2298 
2299   // Avoid artificial faces
2300   TopTools_MapOfShape aNewFaces;
2301   if (myAnalyzer)
2302   {
2303     TopTools_MapOfShape aMapNewTmp;
2304     for (TopTools_ListOfShape::Iterator it (myAnalyzer->NewFaces()); it.More(); it.Next())
2305       aMapNewTmp.Add (it.Value());
2306 
2307     for (TopTools_ListOfShape::Iterator it (theLFOffset); it.More(); it.Next())
2308     {
2309       const TopoDS_Shape& aFOffset = it.Value();
2310       const TopoDS_Shape& aFOrigin = myFacesOrigins->Find (aFOffset);
2311       if (aMapNewTmp.Contains (aFOrigin))
2312         aNewFaces.Add (aFOffset);
2313     }
2314   }
2315 
2316   TopTools_IndexedDataMapOfShapeListOfShape anEFMap;
2317   for (TopTools_ListOfShape::Iterator itLFO (theLFOffset); itLFO.More(); itLFO.Next())
2318   {
2319     const TopoDS_Shape& aF = itLFO.Value();
2320     if (aNewFaces.Contains (aF))
2321       continue;
2322 
2323     const TopTools_ListOfShape& aLFImages = myOFImages.FindFromKey (aF);
2324     for (TopTools_ListOfShape::Iterator itLF (aLFImages); itLF.More(); itLF.Next())
2325     {
2326       const TopoDS_Shape& aFIm = itLF.Value();
2327 
2328       TopExp::MapShapesAndAncestors (aFIm, TopAbs_EDGE, TopAbs_FACE, anEFMap);
2329 
2330       const TopTools_IndexedMapOfShape* pMEInvalid = theLocInvEdges.Seek (aFIm);
2331       const TopTools_MapOfShape* pMEValid = theLocValidEdges.Seek (aFIm);
2332 
2333       for (TopExp_Explorer expE (aFIm, TopAbs_EDGE); expE.More(); expE.Next())
2334       {
2335         const TopoDS_Shape& aE = expE.Current();
2336         if (myInvalidEdges.Contains (aE) != myValidEdges.Contains (aE))
2337         {
2338           // edge is classified in some face
2339 
2340           if ((!pMEInvalid || !pMEInvalid->Contains (aE)) &&
2341             (!pMEValid || !pMEValid->Contains (aE)))
2342           {
2343             // but not in the current one
2344             TopTools_MapOfShape* pMap = aMEUnclassified.ChangeSeek (aE);
2345             if (!pMap)
2346               pMap = &aMEUnclassified (aMEUnclassified.Add (aE, TopTools_MapOfShape()));
2347             pMap->Add (aFIm);
2348 
2349             aFSplitFOffset.Bind (aFIm, aF);
2350           }
2351         }
2352       }
2353     }
2354   }
2355 
2356   if (aMEUnclassified.IsEmpty())
2357     return;
2358 
2359   // Analyze unclassified edges
2360   const Standard_Integer aNbE = aMEUnclassified.Extent();
2361   for (Standard_Integer iE = 1; iE <= aNbE; ++iE)
2362   {
2363     const TopoDS_Shape& aE = aMEUnclassified.FindKey (iE);
2364     const TopTools_MapOfShape& aMFUnclassified = aMEUnclassified (iE);
2365 
2366     const TopTools_ListOfShape& aLF = anEFMap.FindFromKey (aE);
2367 
2368     for (TopTools_ListOfShape::Iterator itLF (aLF); itLF.More(); itLF.Next())
2369     {
2370       const TopoDS_Shape& aFClassified = itLF.Value();
2371       if (aMFUnclassified.Contains (aFClassified))
2372         continue;
2373 
2374       BOPTools_Set anEdgeSetClass;
2375       anEdgeSetClass.Add (aFClassified, TopAbs_EDGE);
2376 
2377       TopoDS_Shape aEClassified;
2378       FindShape (aE, aFClassified, NULL, aEClassified);
2379       TopAbs_Orientation anOriClass = aEClassified.Orientation();
2380 
2381       gp_Dir aDNClass;
2382       BOPTools_AlgoTools3D::GetNormalToFaceOnEdge (TopoDS::Edge (aEClassified), TopoDS::Face (aFClassified), aDNClass);
2383 
2384       const TopTools_IndexedMapOfShape* pMEInvalid = theLocInvEdges.Seek (aFClassified);
2385       Standard_Boolean isInvalid = pMEInvalid && pMEInvalid->Contains (aE);
2386 
2387       for (TopTools_MapOfShape::Iterator itM (aMFUnclassified); itM.More(); itM.Next())
2388       {
2389         const TopoDS_Shape& aFUnclassified = itM.Value();
2390 
2391         BOPTools_Set anEdgeSetUnclass;
2392         anEdgeSetUnclass.Add (aFUnclassified, TopAbs_EDGE);
2393 
2394         if (anEdgeSetClass.IsEqual (anEdgeSetUnclass))
2395         {
2396           gp_Dir aDNUnclass;
2397           BOPTools_AlgoTools3D::GetNormalToFaceOnEdge (TopoDS::Edge (aE), TopoDS::Face (aFUnclassified), aDNUnclass);
2398 
2399           Standard_Boolean isSameOri = aDNClass.IsEqual (aDNUnclass, Precision::Angular());
2400 
2401           // Among other splits of the same face find those where the edge is contained with different
2402           // orientation
2403           const TopoDS_Shape& aFOffset = aFSplitFOffset.Find (aFUnclassified);
2404           const TopTools_ListOfShape& aLFSplits = myOFImages.FindFromKey (aFOffset);
2405           TopTools_ListOfShape::Iterator itLFSp (aLFSplits);
2406           for (; itLFSp.More(); itLFSp.Next())
2407           {
2408             const TopoDS_Shape& aFSp = itLFSp.Value();
2409 
2410             if (!aFSp.IsSame (aFUnclassified) && aMFUnclassified.Contains (aFSp))
2411             {
2412               TopoDS_Shape aEUnclassified;
2413               FindShape (aE, aFSp, NULL, aEUnclassified);
2414 
2415               TopAbs_Orientation anOriUnclass = aEUnclassified.Orientation();
2416               if (!isSameOri)
2417                 anOriUnclass = TopAbs::Reverse (anOriUnclass);
2418 
2419               if (anOriClass != anOriUnclass)
2420               {
2421                 // make the edge neutral for the face
2422                 TopTools_MapOfShape* pMENeutral = theNeutralEdges.ChangeSeek (aFOffset);
2423                 if (!pMENeutral)
2424                   pMENeutral = theNeutralEdges.Bound (aFOffset, TopTools_MapOfShape());
2425                 pMENeutral->Add (aE);
2426 
2427                 if (isInvalid && isSameOri)
2428                 {
2429                   // make edge invalid in aFUnclassified and valid in aFSp
2430                   addAsNeutral (aE, aFClassified, aFSp, theLocInvEdges, theLocValidEdges);
2431                 }
2432                 else
2433                 {
2434                   // make edge invalid in aFSp and valid in aFUnclassified
2435                   addAsNeutral (aE, aFSp, aFClassified, theLocInvEdges, theLocValidEdges);
2436                 }
2437               }
2438             }
2439           }
2440           if (itLFSp.More())
2441             break;
2442         }
2443       }
2444     }
2445   }
2446 }
2447 
2448 //=======================================================================
2449 //function : MakeInvertedEdgesInvalid
2450 //purpose  : Makes inverted edges located inside loop of invalid edges, invalid as well
2451 //=======================================================================
MakeInvertedEdgesInvalid(const TopTools_ListOfShape & theLFOffset)2452 void BRepOffset_BuildOffsetFaces::MakeInvertedEdgesInvalid (const TopTools_ListOfShape& theLFOffset)
2453 {
2454   if (myInvalidEdges.IsEmpty() || myInvertedEdges.IsEmpty())
2455     return;
2456 
2457   // Map all invalid edges
2458   TopoDS_Compound aCBEInv;
2459   BRep_Builder().MakeCompound (aCBEInv);
2460   for (Standard_Integer i = 1; i <= myInvalidEdges.Extent(); ++i)
2461   {
2462     BRep_Builder().Add (aCBEInv, myInvalidEdges (i));
2463   }
2464 
2465   // Make loops of invalid edges
2466   TopTools_ListOfShape aLCB;
2467   BOPTools_AlgoTools::MakeConnexityBlocks (aCBEInv, TopAbs_VERTEX, TopAbs_EDGE, aLCB);
2468 
2469   // Analyze each loop on closeness and use only closed ones
2470   TopTools_DataMapOfShapeShape aDMVCB;
2471 
2472   for (TopTools_ListOfShape::Iterator itLCB (aLCB); itLCB.More(); itLCB.Next())
2473   {
2474     const TopoDS_Shape& aCB = itLCB.Value();
2475 
2476     TopTools_IndexedDataMapOfShapeListOfShape aDMVE;
2477     TopExp::MapShapesAndAncestors (aCB, TopAbs_VERTEX, TopAbs_EDGE, aDMVE);
2478     Standard_Boolean isClosed = Standard_True;
2479     for (Standard_Integer iV = 1; iV <= aDMVE.Extent(); ++iV)
2480     {
2481       if (aDMVE (iV).Extent() != 2)
2482       {
2483         isClosed = Standard_False;
2484         break;
2485       }
2486     }
2487     if (!isClosed)
2488       continue;
2489 
2490     // Bind loop to each vertex of the loop
2491     for (Standard_Integer iV = 1; iV <= aDMVE.Extent(); ++iV)
2492     {
2493       aDMVCB.Bind (aDMVE.FindKey (iV), aCB);
2494     }
2495   }
2496 
2497   // Check if any inverted edges of offset faces are locked inside the loops of invalid edges.
2498   // Make such edges invalid as well.
2499   for (TopTools_ListOfShape::Iterator itLF (theLFOffset); itLF.More(); itLF.Next())
2500   {
2501     const TopTools_ListOfShape& aLFIm = myOFImages.FindFromKey (itLF.Value());
2502     for (TopTools_ListOfShape::Iterator itLFIm (aLFIm); itLFIm.More(); itLFIm.Next())
2503     {
2504       for (TopExp_Explorer expE (itLFIm.Value(), TopAbs_EDGE); expE.More(); expE.Next())
2505       {
2506         const TopoDS_Edge& aE = TopoDS::Edge (expE.Current());
2507         if (!myInvalidEdges.Contains (aE) && myInvertedEdges.Contains (aE))
2508         {
2509           const TopoDS_Shape* pCB1 = aDMVCB.Seek (TopExp::FirstVertex (aE));
2510           const TopoDS_Shape* pCB2 = aDMVCB.Seek (TopExp::LastVertex (aE));
2511           if (pCB1 && pCB2 && pCB1->IsSame (*pCB2))
2512           {
2513             myInvalidEdges.Add (aE);
2514           }
2515         }
2516       }
2517     }
2518   }
2519 }
2520 
2521 //=======================================================================
2522 //function : FindInvalidFaces
2523 //purpose  : Looking for the invalid faces by analyzing their invalid edges
2524 //=======================================================================
FindInvalidFaces(TopTools_ListOfShape & theLFImages,const BRepOffset_DataMapOfShapeMapOfShape & theDMFMVE,const BRepOffset_DataMapOfShapeIndexedMapOfShape & theDMFMIE,const TopTools_MapOfShape & theMENeutral,const TopTools_MapOfShape & theEdgesInvalidByVertex,const TopTools_MapOfShape & theEdgesValidByVertex,const TopTools_MapOfShape & theMFHoles,TopTools_IndexedMapOfShape & theMFInvInHole,TopTools_ListOfShape & theInvFaces,TopTools_ListOfShape & theInvertedFaces)2525 void BRepOffset_BuildOffsetFaces::FindInvalidFaces (TopTools_ListOfShape& theLFImages,
2526                                                     const BRepOffset_DataMapOfShapeMapOfShape& theDMFMVE,
2527                                                     const BRepOffset_DataMapOfShapeIndexedMapOfShape& theDMFMIE,
2528                                                     const TopTools_MapOfShape& theMENeutral,
2529                                                     const TopTools_MapOfShape& theEdgesInvalidByVertex,
2530                                                     const TopTools_MapOfShape& theEdgesValidByVertex,
2531                                                     const TopTools_MapOfShape& theMFHoles,
2532                                                     TopTools_IndexedMapOfShape& theMFInvInHole,
2533                                                     TopTools_ListOfShape& theInvFaces,
2534                                                     TopTools_ListOfShape& theInvertedFaces)
2535 {
2536   // The face should be considered as invalid in the following cases:
2537   // 1. It has been reverted, i.e. at least two not connected edges
2538   //    have changed orientation (i.e. invalid). In this case all edges,
2539   //    should be invalid for that face, because edges have also been reverted;
2540   // 2. All checked edges of the face are invalid for this face;
2541   // The face should be removed from the splits in the following cases:
2542   // 1. All checked edges of the face are invalid for this one, but valid for
2543   //    some other face in this list of splits.
2544   // The face will be kept in the following cases:
2545   // 1. Some of the edges are valid for this face.
2546   Standard_Boolean bHasValid, bAllValid, bAllInvalid, bHasReallyInvalid, bAllInvNeutral;
2547   Standard_Boolean bValid, bValidLoc, bInvalid, bInvalidLoc, bNeutral, bInverted;
2548   Standard_Boolean bIsInvalidByInverted, bHasInverted;
2549   Standard_Integer aNbChecked;
2550   //
2551   Standard_Boolean bTreatInvertedAsInvalid = (theLFImages.Extent() == 1);
2552   //
2553   // neutral edges to remove
2554   TopTools_IndexedMapOfShape aMENRem;
2555   //
2556   // faces for post treat
2557   TopTools_ListOfShape aLFPT;
2558   //
2559   TopTools_IndexedDataMapOfShapeListOfShape aDMEF;
2560   TopTools_ListIteratorOfListOfShape aItLF (theLFImages);
2561   for (; aItLF.More(); aItLF.Next())
2562   {
2563     const TopoDS_Face& aFIm = *(TopoDS_Face*)&aItLF.Value();
2564     TopExp::MapShapesAndAncestors (aFIm, TopAbs_EDGE, TopAbs_FACE, aDMEF);
2565   }
2566 
2567   aItLF.Initialize (theLFImages);
2568   for (; aItLF.More(); )
2569   {
2570     const TopoDS_Face& aFIm = *(TopoDS_Face*)&aItLF.Value();
2571     //
2572     // valid edges for this split
2573     const TopTools_MapOfShape* pMVE = theDMFMVE.Seek (aFIm);
2574     // invalid edges for this split
2575     const TopTools_IndexedMapOfShape* pMIE = theDMFMIE.Seek (aFIm);
2576     //
2577     bHasValid = Standard_False;
2578     bAllValid = Standard_True;
2579     bAllInvalid = Standard_True;
2580     bHasReallyInvalid = Standard_False;
2581     bAllInvNeutral = Standard_True;
2582     bIsInvalidByInverted = Standard_True;
2583     bHasInverted = Standard_False;
2584     aNbChecked = 0;
2585     //
2586     const TopoDS_Wire& aWIm = BRepTools::OuterWire (aFIm);
2587     TopExp_Explorer aExp (aWIm, TopAbs_EDGE);
2588     for (; aExp.More(); aExp.Next())
2589     {
2590       const TopoDS_Shape& aEIm = aExp.Current();
2591       //
2592       bValid = myValidEdges.Contains (aEIm);
2593       bInvalid = myInvalidEdges.Contains (aEIm);
2594       bNeutral = theMENeutral.Contains (aEIm);
2595       //
2596       if (!bValid && !bInvalid && !bNeutral)
2597       {
2598         // edge has not been checked for some reason
2599         continue;
2600       }
2601 
2602       // skip not-boundary edges originated from vertex
2603       if ((theEdgesInvalidByVertex.Contains (aEIm) ||
2604            theEdgesValidByVertex.Contains (aEIm)) &&
2605           aDMEF.FindFromKey (aEIm).Extent() != 1)
2606         continue;
2607 
2608       ++aNbChecked;
2609       //
2610       bInvalidLoc = pMIE && pMIE->Contains (aEIm);
2611       bHasReallyInvalid = bInvalid && bInvalidLoc && !bValid && !theEdgesInvalidByVertex.Contains (aEIm);
2612       if (bHasReallyInvalid)
2613       {
2614         break;
2615       }
2616       //
2617       bValidLoc = pMVE && pMVE->Contains (aEIm);
2618       bInverted = myInvertedEdges.Contains (aEIm);
2619       if (!bInvalid && !bInvalidLoc && bTreatInvertedAsInvalid)
2620       {
2621         bInvalid = bInverted;
2622       }
2623       //
2624       if (bValidLoc && bNeutral)
2625       {
2626         bHasValid = Standard_True;
2627       }
2628       //
2629       bAllValid &= bValidLoc;
2630       bAllInvalid &= (bInvalid || bInvalidLoc);
2631       bAllInvNeutral &= (bAllInvalid && bNeutral);
2632       bIsInvalidByInverted &= (bInvalidLoc || bInverted);
2633       bHasInverted |= bInverted;
2634     }
2635     //
2636     if (!aNbChecked)
2637     {
2638       aItLF.Next();
2639       continue;
2640     }
2641     //
2642     if (!bHasReallyInvalid && (bAllInvNeutral && !bHasValid) && (aNbChecked > 1))
2643     {
2644       if (bHasInverted)
2645       {
2646         // The part seems to be filled due to overlapping of parts rather than
2647         // due to multi-connection of faces. No need to remove the part.
2648         aItLF.Next();
2649         continue;
2650       }
2651       // remove edges from neutral
2652       TopExp::MapShapes (aFIm, TopAbs_EDGE, aMENRem);
2653       // remove face
2654       theLFImages.Remove (aItLF);
2655       continue;
2656     }
2657     //
2658     if (bHasReallyInvalid || (bAllInvalid &&
2659                               !(bHasValid || bAllValid) &&
2660                               !(bAllInvNeutral && (aNbChecked == 1))))
2661     {
2662       theInvFaces.Append (aFIm);
2663       if (theMFHoles.Contains (aFIm))
2664       {
2665         theMFInvInHole.Add (aFIm);
2666       }
2667       aItLF.Next();
2668       continue;
2669     }
2670     //
2671     if (theMFHoles.Contains (aFIm))
2672     {
2673       // remove edges from neutral
2674       TopExp::MapShapes (aFIm, TopAbs_EDGE, aMENRem);
2675       // remove face
2676       theLFImages.Remove (aItLF);
2677       continue;
2678     }
2679     //
2680     if (bIsInvalidByInverted && !(bHasValid || bAllValid))
2681     {
2682       // The face contains only the inverted and locally invalid edges
2683       theInvertedFaces.Append (aFIm);
2684     }
2685 
2686     if (!bAllInvNeutral)
2687     {
2688       aLFPT.Append (aFIm);
2689     }
2690     else
2691     {
2692       // remove edges from neutral
2693       TopExp::MapShapes (aFIm, TopAbs_EDGE, aMENRem);
2694     }
2695     aItLF.Next();
2696   }
2697   //
2698   if (aLFPT.IsEmpty() || aMENRem.IsEmpty())
2699   {
2700     return;
2701   }
2702 
2703   // check the splits once more
2704   aItLF.Initialize (aLFPT);
2705   for (; aItLF.More(); aItLF.Next())
2706   {
2707     const TopoDS_Face& aFIm = *(TopoDS_Face*)&aItLF.Value();
2708     //
2709     // valid edges for this split
2710     const TopTools_MapOfShape* pMVE = theDMFMVE.Seek (aFIm);
2711     //
2712     bHasValid = Standard_False;
2713     bAllValid = Standard_True;
2714     bAllInvalid = Standard_True;
2715     //
2716     const TopoDS_Wire& aWIm = BRepTools::OuterWire (aFIm);
2717     TopExp_Explorer aExp (aWIm, TopAbs_EDGE);
2718     for (; aExp.More(); aExp.Next())
2719     {
2720       const TopoDS_Shape& aEIm = aExp.Current();
2721       //
2722       bValid = myValidEdges.Contains (aEIm);
2723       bInvalid = myInvalidEdges.Contains (aEIm);
2724       bNeutral = theMENeutral.Contains (aEIm) && !aMENRem.Contains (aEIm);
2725       bValidLoc = pMVE && pMVE->Contains (aEIm);
2726       //
2727       if (!bInvalid && bTreatInvertedAsInvalid)
2728       {
2729         bInvalid = myInvertedEdges.Contains (aEIm);
2730       }
2731       //
2732       if (bValidLoc && bNeutral)
2733       {
2734         bHasValid = Standard_True;
2735       }
2736       //
2737       bAllValid = bAllValid && bValidLoc;
2738       bAllInvalid = bAllInvalid && bInvalid;
2739     }
2740     //
2741     if (bAllInvalid && !bHasValid && !bAllValid)
2742     {
2743       theInvFaces.Append (aFIm);
2744     }
2745   }
2746 }
2747 
2748 //=======================================================================
2749 //function : FindFacesInsideHoleWires
2750 //purpose  : Find faces inside holes wires from the original face
2751 //=======================================================================
FindFacesInsideHoleWires(const TopoDS_Face & theFOrigin,const TopoDS_Face & theFOffset,const TopTools_ListOfShape & theLFImages,const TopTools_DataMapOfShapeListOfShape & theDMEOrLEIm,const TopTools_IndexedDataMapOfShapeListOfShape & theEFMap,TopTools_MapOfShape & theMFHoles)2752 void BRepOffset_BuildOffsetFaces::FindFacesInsideHoleWires (const TopoDS_Face& theFOrigin,
2753                                                             const TopoDS_Face& theFOffset,
2754                                                             const TopTools_ListOfShape& theLFImages,
2755                                                             const TopTools_DataMapOfShapeListOfShape& theDMEOrLEIm,
2756                                                             const TopTools_IndexedDataMapOfShapeListOfShape& theEFMap,
2757                                                             TopTools_MapOfShape& theMFHoles)
2758 {
2759   if (theLFImages.IsEmpty())
2760   {
2761     return;
2762   }
2763   //
2764   // find all hole wires in the original face
2765   TopTools_ListOfShape aLHoleWires;
2766   const TopoDS_Wire& anOuterWire = BRepTools::OuterWire (theFOrigin);
2767   TopExp_Explorer aExpW (theFOrigin, TopAbs_WIRE);
2768   for (; aExpW.More(); aExpW.Next())
2769   {
2770     const TopoDS_Wire& aHoleWire = TopoDS::Wire (aExpW.Current());
2771     if (!aHoleWire.IsSame (anOuterWire) && aHoleWire.Orientation() != TopAbs_INTERNAL)
2772     {
2773       aLHoleWires.Append (aHoleWire);
2774     }
2775   }
2776   //
2777   if (aLHoleWires.IsEmpty())
2778   {
2779     // no holes in the face
2780     return;
2781   }
2782   //
2783   TopTools_ListOfShape* pLFNewHoles = myFNewHoles.ChangeSeek (theFOrigin);
2784   //
2785   if (!pLFNewHoles)
2786   {
2787     pLFNewHoles = myFNewHoles.Bound (theFOrigin, TopTools_ListOfShape());
2788   }
2789   if (pLFNewHoles->IsEmpty())
2790   {
2791     //
2792     // find the faces representing holes in the images of the faces:
2793     // 1. for each original hole wire try to build its image
2794     // 2. build the new planar face from the images
2795     //
2796     // map vertices and edges of the splits
2797     TopTools_IndexedMapOfShape aMESplits;
2798     TopTools_ListIteratorOfListOfShape aItLF (theLFImages);
2799     for (; aItLF.More(); aItLF.Next())
2800     {
2801       TopExp::MapShapes (aItLF.Value(), TopAbs_EDGE, aMESplits);
2802     }
2803     //
2804     TopTools_ListIteratorOfListOfShape aItLW (aLHoleWires);
2805     for (; aItLW.More(); aItLW.Next())
2806     {
2807       const TopoDS_Wire& aHoleWire = TopoDS::Wire (aItLW.Value());
2808       // find images of all edges of the original wire
2809       TopTools_IndexedMapOfShape aMEImWire;
2810       TopoDS_Iterator aItE (aHoleWire);
2811       for (; aItE.More(); aItE.Next())
2812       {
2813         const TopoDS_Shape& aEOr = aItE.Value();
2814         const TopTools_ListOfShape* pLEIm = theDMEOrLEIm.Seek (aEOr);
2815         if (!pLEIm || pLEIm->IsEmpty())
2816         {
2817           continue;
2818         }
2819         TopTools_ListIteratorOfListOfShape aItLEIm (*pLEIm);
2820         for (; aItLEIm.More(); aItLEIm.Next())
2821         {
2822           const TopoDS_Shape& aEIm = aItLEIm.Value();
2823           if (aMESplits.Contains (aEIm))
2824           {
2825             aMEImWire.Add (aEIm);
2826           }
2827         }
2828       }
2829       //
2830       if (aMEImWire.IsEmpty())
2831       {
2832         continue;
2833       }
2834       //
2835       // build new planar face using these edges
2836       TopTools_ListOfShape aLE;
2837       Standard_Integer i, aNbE = aMEImWire.Extent();
2838       for (i = 1; i <= aNbE; ++i)
2839       {
2840         aLE.Append (aMEImWire (i).Oriented (TopAbs_FORWARD));
2841         aLE.Append (aMEImWire (i).Oriented (TopAbs_REVERSED));
2842       }
2843       //
2844       BOPAlgo_BuilderFace aBF;
2845       aBF.SetFace (TopoDS::Face (theFOffset.Oriented (TopAbs_FORWARD)));
2846       aBF.SetShapes (aLE);
2847       aBF.Perform();
2848       //
2849       const TopTools_ListOfShape& aLFNew = aBF.Areas();
2850       if (aLFNew.IsEmpty())
2851       {
2852         continue;
2853       }
2854       //
2855       // check if outer edges in the new faces are not inverted
2856       // because the inverted edges mean that the hole has been
2857       // filled during offset and there will be no faces to remove
2858       TopTools_IndexedDataMapOfShapeListOfShape aDMEFNew;
2859       TopTools_ListIteratorOfListOfShape aItLFNew (aLFNew);
2860       for (; aItLFNew.More(); aItLFNew.Next())
2861       {
2862         TopExp::MapShapesAndAncestors (aItLFNew.Value(), TopAbs_EDGE, TopAbs_FACE, aDMEFNew);
2863       }
2864       //
2865       aNbE = aDMEFNew.Extent();
2866       for (i = 1; i <= aNbE; ++i)
2867       {
2868         if (aDMEFNew (i).Extent() == 1)
2869         {
2870           const TopoDS_Shape& aE = aDMEFNew.FindKey (i);
2871           if (myInvertedEdges.Contains (aE))
2872           {
2873             break;
2874           }
2875         }
2876       }
2877       //
2878       if (i <= aNbE)
2879       {
2880         continue;
2881       }
2882       //
2883       aItLFNew.Initialize (aLFNew);
2884       for (; aItLFNew.More(); aItLFNew.Next())
2885       {
2886         pLFNewHoles->Append (aItLFNew.Value());
2887       }
2888     }
2889   }
2890 
2891   // Build Edge-Face map for splits of current offset face
2892   TopTools_IndexedDataMapOfShapeListOfShape anEFSplitsMap;
2893   // Build Edge-Face map for holes
2894   TopTools_IndexedDataMapOfShapeListOfShape anEFHolesMap;
2895 
2896   // among the splits of the offset face find those that are
2897   // located inside the hole faces
2898   TopTools_ListIteratorOfListOfShape aItLF (theLFImages);
2899   for (; aItLF.More(); aItLF.Next())
2900   {
2901     const TopoDS_Face& aFIm = TopoDS::Face (aItLF.Value());
2902     TopExp::MapShapesAndAncestors (aFIm, TopAbs_EDGE, TopAbs_FACE, anEFSplitsMap);
2903     // get the point inside the face and classify it relatively hole faces
2904     gp_Pnt aP3D;
2905     gp_Pnt2d aP2D;
2906     Standard_Integer iErr = BOPTools_AlgoTools3D::PointInFace (aFIm, aP3D, aP2D, myContext);
2907     if (iErr)
2908     {
2909       continue;
2910     }
2911     //
2912     Standard_Real aTol = BRep_Tool::Tolerance (aFIm);
2913     //
2914     TopTools_ListIteratorOfListOfShape aItLFNew (*pLFNewHoles);
2915     for (; aItLFNew.More(); aItLFNew.Next())
2916     {
2917       const TopoDS_Face& aFNew = TopoDS::Face (aItLFNew.Value());
2918       if (myContext->IsValidPointForFace (aP3D, aFNew, aTol))
2919       {
2920         // the face is classified as IN
2921         theMFHoles.Add (aFIm);
2922         TopExp::MapShapesAndAncestors (aFIm, TopAbs_EDGE, TopAbs_FACE, anEFHolesMap);
2923         break;
2924       }
2925     }
2926   }
2927 
2928   // Out of all found holes find those which cannot be removed
2929   // by checking their connectivity to splits of other offset faces.
2930   // These are the faces, which will create uncovered holes if removed.
2931   const Standard_Integer aNbE = anEFHolesMap.Extent();
2932   for (Standard_Integer i = 1; i <= aNbE; ++i)
2933   {
2934     const TopoDS_Shape& anEdge = anEFHolesMap.FindKey (i);
2935     const TopTools_ListOfShape& aLFHoles = anEFHolesMap (i);
2936     // Check if the edge is outer for holes
2937     if (aLFHoles.Extent() != 1)
2938       continue;
2939 
2940     const TopoDS_Shape& aFHole = aLFHoles.First();
2941     if (!theMFHoles.Contains (aFHole))
2942       // Already removed
2943       continue;
2944 
2945     // Check if the edge is not outer for splits
2946     const TopTools_ListOfShape& aLSplits = anEFSplitsMap.FindFromKey (anEdge);
2947     if (aLSplits.Extent() == 1)
2948       continue;
2949 
2950     // Check if edge is only connected to splits of the current offset face
2951     const TopTools_ListOfShape& aLFAll = theEFMap.FindFromKey (anEdge);
2952     if (aLFAll.Extent() == 2)
2953       // Avoid removal of the hole from the splits
2954       theMFHoles.Remove (aFHole);
2955   }
2956 }
2957 
2958 //=======================================================================
2959 //function : CheckInverted
2960 //purpose  : Checks if the edge has been inverted
2961 //=======================================================================
CheckInverted(const TopoDS_Edge & theEIm,const TopoDS_Face & theFOr,const TopTools_IndexedDataMapOfShapeListOfShape & theDMVE,const TopTools_IndexedMapOfShape & theMEdges)2962 Standard_Boolean BRepOffset_BuildOffsetFaces::CheckInverted (const TopoDS_Edge& theEIm,
2963                                                              const TopoDS_Face& theFOr,
2964                                                              const TopTools_IndexedDataMapOfShapeListOfShape& theDMVE,
2965                                                              const TopTools_IndexedMapOfShape& theMEdges)
2966 {
2967   // It is necessary to compare the direction from first vertex
2968   // to the last vertex on the original edge with the
2969   // same direction on the new edge. If the directions
2970   // will be different - the edge has been inverted.
2971   //
2972   TopoDS_Vertex aVI1, aVI2; // vertices on the offset edge
2973   TopoDS_Vertex aVO1, aVO2; // vertices on the original edge
2974   //
2975   Standard_Integer i;
2976   // find vertices of the offset shape
2977   TopExp::Vertices (theEIm, aVI1, aVI2);
2978   //
2979   // find images
2980   TopTools_ListOfShape aLEImages;
2981   if (myOEOrigins.IsBound (theEIm))
2982   {
2983     TopoDS_Wire anImages;
2984     BRep_Builder().MakeWire (anImages);
2985     //
2986     TopTools_MapOfShape aMImFence;
2987     const TopTools_ListOfShape& aLOffsetOr = myOEOrigins.Find (theEIm);
2988     TopTools_ListIteratorOfListOfShape aItOffset (aLOffsetOr);
2989     for (; aItOffset.More(); aItOffset.Next())
2990     {
2991       const TopoDS_Shape& aEOffsetOr = aItOffset.Value();
2992       const TopTools_ListOfShape& aLImages = myOEImages.Find (aEOffsetOr);
2993       //
2994       TopTools_ListIteratorOfListOfShape aItImages (aLImages);
2995       for (; aItImages.More(); aItImages.Next())
2996       {
2997         const TopoDS_Edge& anIm = *(TopoDS_Edge*)&aItImages.Value();
2998         if (theMEdges.Contains (anIm) && aMImFence.Add (anIm))
2999         {
3000           BRep_Builder().Add (anImages, anIm);
3001           aLEImages.Append (anIm);
3002         }
3003       }
3004     }
3005     //
3006     // find alone vertices
3007     TopoDS_Vertex aVW1, aVW2;
3008     TopTools_IndexedDataMapOfShapeListOfShape aDMImVE;
3009     TopExp::MapShapesAndAncestors (anImages, TopAbs_VERTEX, TopAbs_EDGE, aDMImVE);
3010     //
3011     TopTools_ListOfShape aLVAlone;
3012     Standard_Integer aNb = aDMImVE.Extent();
3013     for (i = 1; i <= aNb; ++i)
3014     {
3015       const TopTools_ListOfShape& aLImE = aDMImVE (i);
3016       if (aLImE.Extent() == 1)
3017       {
3018         aLVAlone.Append (aDMImVE.FindKey (i));
3019       }
3020     }
3021     //
3022     if (aLVAlone.Extent() > 1)
3023     {
3024       aVW1 = *(TopoDS_Vertex*)&aLVAlone.First();
3025       aVW2 = *(TopoDS_Vertex*)&aLVAlone.Last();
3026       //
3027       // check distances
3028       const gp_Pnt& aPI1 = BRep_Tool::Pnt (aVI1);
3029       const gp_Pnt& aPW1 = BRep_Tool::Pnt (aVW1);
3030       const gp_Pnt& aPW2 = BRep_Tool::Pnt (aVW2);
3031       //
3032       Standard_Real aDist1 = aPI1.SquareDistance (aPW1);
3033       Standard_Real aDist2 = aPI1.SquareDistance (aPW2);
3034       //
3035       if (aDist1 < aDist2)
3036       {
3037         aVI1 = aVW1;
3038         aVI2 = aVW2;
3039       }
3040       else
3041       {
3042         aVI1 = aVW2;
3043         aVI2 = aVW1;
3044       }
3045     }
3046   }
3047   else
3048   {
3049     aLEImages.Append (theEIm);
3050   }
3051   //
3052   // Find edges connected to these vertices
3053   const TopTools_ListOfShape& aLIE1 = theDMVE.FindFromKey (aVI1);
3054   const TopTools_ListOfShape& aLIE2 = theDMVE.FindFromKey (aVI2);
3055   //
3056   // Find vertices on the original face corresponding to vertices on the offset edge
3057   //
3058   // find original edges for both lists
3059   TopTools_ListOfShape aLOE1, aLOE2;
3060   for (i = 0; i < 2; ++i)
3061   {
3062     const TopTools_ListOfShape& aLIE = !i ? aLIE1 : aLIE2;
3063     TopTools_ListOfShape& aLOE = !i ? aLOE1 : aLOE2;
3064     //
3065     TopTools_MapOfShape aMFence;
3066     //
3067     TopTools_ListIteratorOfListOfShape aItLIE (aLIE);
3068     for (; aItLIE.More(); aItLIE.Next())
3069     {
3070       const TopoDS_Shape& aEI = aItLIE.Value();
3071       if (myEdgesOrigins->IsBound (aEI))
3072       {
3073         const TopTools_ListOfShape& aLEOrigins = myEdgesOrigins->Find (aEI);
3074         //
3075         TopTools_ListIteratorOfListOfShape aItLOE (aLEOrigins);
3076         for (; aItLOE.More(); aItLOE.Next())
3077         {
3078           const TopoDS_Shape& aEO = aItLOE.Value();
3079           if (aEO.ShapeType() == TopAbs_EDGE && aMFence.Add (aEO))
3080           {
3081             TopoDS_Shape aEOin;
3082             if (FindShape (aEO, theFOr, NULL, aEOin))
3083             {
3084               AppendToList (aLOE, aEO);
3085             }
3086           }
3087         }
3088       }
3089     }
3090   }
3091   //
3092   if (aLOE1.Extent() < 2 || aLOE2.Extent() < 2)
3093   {
3094     return Standard_False;
3095   }
3096   //
3097   // find vertices common for the max number of edges in the lists
3098   for (i = 0; i < 2; ++i)
3099   {
3100     const TopTools_ListOfShape& aLOE = !i ? aLOE1 : aLOE2;
3101     TopoDS_Vertex& aVO = !i ? aVO1 : aVO2;
3102 
3103     TopTools_IndexedDataMapOfShapeListOfShape aDMVELoc;
3104     for (TopTools_ListOfShape::Iterator itLOE (aLOE); itLOE.More(); itLOE.Next())
3105     {
3106       TopExp::MapShapesAndAncestors (itLOE.Value(), TopAbs_VERTEX, TopAbs_EDGE, aDMVELoc);
3107     }
3108 
3109     Standard_Integer aNbEMax = 0;
3110     for (Standard_Integer j = 1; j <= aDMVELoc.Extent(); ++j)
3111     {
3112       Standard_Integer aNbE = aDMVELoc (j).Extent();
3113       if (aNbE > 1 && aNbE > aNbEMax)
3114       {
3115         aVO = TopoDS::Vertex (aDMVELoc.FindKey (j));
3116         aNbEMax = aNbE;
3117       }
3118     }
3119     if (aVO.IsNull())
3120     {
3121       return Standard_False;
3122     }
3123   }
3124 
3125   if (aVO1.IsSame (aVO2))
3126   {
3127     return Standard_False;
3128   }
3129   //
3130   // check positions of the offset and original vertices
3131   const gp_Pnt& aPI1 = BRep_Tool::Pnt (aVI1);
3132   const gp_Pnt& aPI2 = BRep_Tool::Pnt (aVI2);
3133   const gp_Pnt& aPO1 = BRep_Tool::Pnt (aVO1);
3134   const gp_Pnt& aPO2 = BRep_Tool::Pnt (aVO2);
3135   //
3136   gp_Vec aVI (aPI1, aPI2);
3137   gp_Vec aVO (aPO1, aPO2);
3138   //
3139   Standard_Real anAngle = aVI.Angle (aVO);
3140   Standard_Boolean bInverted = Abs (anAngle - M_PI) < 1.e-4;
3141   if (bInverted)
3142   {
3143     TopTools_ListIteratorOfListOfShape aItLEIm (aLEImages);
3144     for (; aItLEIm.More(); aItLEIm.Next())
3145     {
3146       const TopoDS_Shape& aEInvr = aItLEIm.Value();
3147       myInvertedEdges.Add (aEInvr);
3148     }
3149   }
3150   return bInverted;
3151 }
3152 
3153 namespace {
3154   //=======================================================================
3155   //function : GetVerticesOnEdges
3156   //purpose  : Get vertices from the given shape belonging to the given edges
3157   //=======================================================================
GetVerticesOnEdges(const TopoDS_Shape & theCB,const TopTools_IndexedMapOfShape & theEdges,TopTools_MapOfShape & theVerticesOnEdges,TopTools_MapOfShape & theAllVertices)3158   static void GetVerticesOnEdges (const TopoDS_Shape& theCB,
3159                                   const TopTools_IndexedMapOfShape& theEdges,
3160                                   TopTools_MapOfShape& theVerticesOnEdges,
3161                                   TopTools_MapOfShape& theAllVertices)
3162   {
3163     TopExp_Explorer aExp (theCB, TopAbs_EDGE);
3164     for (; aExp.More(); aExp.Next())
3165     {
3166       const TopoDS_Shape& aE = aExp.Current();
3167       Standard_Boolean isOnGivenEdges = theEdges.Contains (aE);
3168       for (TopoDS_Iterator aItV (aE); aItV.More(); aItV.Next())
3169       {
3170         theAllVertices.Add (aItV.Value());
3171         if (isOnGivenEdges)
3172         {
3173           theVerticesOnEdges.Add (aItV.Value());
3174         }
3175       }
3176     }
3177   }
3178 }
3179 
3180 //=======================================================================
3181 //function : CheckInvertedBlock
3182 //purpose  : Checks if it is possible to remove the block containing inverted edges
3183 //=======================================================================
CheckInvertedBlock(const TopoDS_Shape & theCB,const TopTools_ListOfShape & theLCBF,BRepOffset_DataMapOfShapeMapOfShape & theDMCBVInverted,BRepOffset_DataMapOfShapeMapOfShape & theDMCBVAll)3184 Standard_Boolean BRepOffset_BuildOffsetFaces::CheckInvertedBlock (const TopoDS_Shape& theCB,
3185                                                                   const TopTools_ListOfShape& theLCBF,
3186                                                                   BRepOffset_DataMapOfShapeMapOfShape& theDMCBVInverted,
3187                                                                   BRepOffset_DataMapOfShapeMapOfShape& theDMCBVAll)
3188 {
3189   // For possible removal of the block:
3190   // 1. There should be more than just one face in the block
3191   if (theCB.NbChildren() < 2)
3192   {
3193     return Standard_False;
3194   }
3195   //
3196   // 2. The block should at least contain two connected inverted edges with
3197   //    different origins (not just two images/splits of the same edge)
3198   TopTools_MapOfShape aMECBInv;
3199   TopoDS_Compound aCECBInv;
3200   BRep_Builder().MakeCompound (aCECBInv);
3201   //
3202   TopExp_Explorer aExp (theCB, TopAbs_EDGE);
3203   for (; aExp.More(); aExp.Next())
3204   {
3205     const TopoDS_Shape& aE = aExp.Current();
3206     if (myInvertedEdges.Contains (aE))
3207     {
3208       if (aMECBInv.Add (aE))
3209       {
3210         BRep_Builder().Add (aCECBInv, aE);
3211       }
3212     }
3213   }
3214   //
3215   if (aMECBInv.Extent() < 2)
3216   {
3217     return Standard_False;
3218   }
3219   //
3220   // check that the edges are connected and different
3221   TopTools_ListOfShape aLCBE;
3222   BOPTools_AlgoTools::MakeConnexityBlocks (aCECBInv, TopAbs_VERTEX, TopAbs_EDGE, aLCBE);
3223   //
3224   TopTools_ListIteratorOfListOfShape aItLCBE (aLCBE);
3225   for (; aItLCBE.More(); aItLCBE.Next())
3226   {
3227     const TopoDS_Shape& aCBE = aItLCBE.Value();
3228     // count the unique edges in the block
3229     Standard_Integer aNbUnique = 0;
3230     TopTools_MapOfShape aMEOrigins;
3231     TopoDS_Iterator aItE (aCBE);
3232     for (; aItE.More(); aItE.Next())
3233     {
3234       const TopoDS_Shape& aE = aItE.Value();
3235       const TopTools_ListOfShape* pLEOr = myOEOrigins.Seek (aE);
3236       if (!pLEOr)
3237       {
3238         aMEOrigins.Add (aE);
3239         ++aNbUnique;
3240         continue;
3241       }
3242       TopTools_ListIteratorOfListOfShape aItLEOr (*pLEOr);
3243       for (; aItLEOr.More(); aItLEOr.Next())
3244       {
3245         const TopoDS_Shape& aEOr = aItLEOr.Value();
3246         if (aMEOrigins.Add (aEOr))
3247         {
3248           ++aNbUnique;
3249         }
3250       }
3251     }
3252     //
3253     if (aNbUnique >= 2)
3254     {
3255       break;
3256     }
3257   }
3258   //
3259   if (!aItLCBE.More())
3260   {
3261     return Standard_False;
3262   }
3263   //
3264   // 3. the block should not contain inverted edges which vertices
3265   //    are contained in other blocks
3266   //
3267   // collect vertices from inverted edges and compare them with
3268   // vertices from other blocks
3269   TopTools_MapOfShape* pMVInverted = theDMCBVInverted.ChangeSeek (theCB);
3270   TopTools_MapOfShape* pMVAll = theDMCBVAll.ChangeSeek (theCB);
3271   if (!pMVInverted)
3272   {
3273     pMVInverted = theDMCBVInverted.Bound (theCB, TopTools_MapOfShape());
3274     pMVAll = theDMCBVAll.Bound (theCB, TopTools_MapOfShape());
3275     //
3276     GetVerticesOnEdges (theCB, myInvertedEdges, *pMVInverted, *pMVAll);
3277   }
3278   //
3279   TopTools_ListIteratorOfListOfShape aItLCB1 (theLCBF);
3280   for (; aItLCB1.More(); aItLCB1.Next())
3281   {
3282     const TopoDS_Shape& aCB1 = aItLCB1.Value();
3283     if (aCB1.IsSame (theCB))
3284     {
3285       continue;
3286     }
3287     //
3288     // collect vertices from inverted edges
3289     TopTools_MapOfShape* pMVInverted1 = theDMCBVInverted.ChangeSeek (aCB1);
3290     TopTools_MapOfShape* pMVAll1 = theDMCBVAll.ChangeSeek (aCB1);
3291     if (!pMVInverted1)
3292     {
3293       pMVInverted1 = theDMCBVInverted.Bound (aCB1, TopTools_MapOfShape());
3294       pMVAll1 = theDMCBVAll.Bound (aCB1, TopTools_MapOfShape());
3295       //
3296       GetVerticesOnEdges (aCB1, myInvertedEdges, *pMVInverted1, *pMVAll1);
3297     }
3298     //
3299     if (pMVInverted->HasIntersection (*pMVAll1))
3300     {
3301       return Standard_False;
3302     }
3303   }
3304   //
3305   return Standard_True;
3306 }
3307 
3308 //=======================================================================
3309 //function : RemoveInvalidSplitsByInvertedEdges
3310 //purpose  : Looking for the invalid faces containing inverted edges
3311 //           that can be safely removed
3312 //=======================================================================
RemoveInvalidSplitsByInvertedEdges(TopTools_IndexedMapOfShape & theMERemoved)3313 void BRepOffset_BuildOffsetFaces::RemoveInvalidSplitsByInvertedEdges (TopTools_IndexedMapOfShape& theMERemoved)
3314 {
3315   if (myInvertedEdges.IsEmpty())
3316   {
3317     return;
3318   }
3319   //
3320   // check the faces on regularity, i.e. the splits of the same face
3321   // should not be connected only by vertex. Such irregular splits
3322   // will have to be rebuilt and cannot be removed.
3323   //
3324   BRep_Builder aBB;
3325   TopTools_IndexedMapOfShape aMEAvoid;
3326   TopTools_DataMapOfShapeListOfShape aDMVF;
3327   Standard_Integer aNb = myOFImages.Extent(), i;
3328   for (i = 1; i <= aNb; ++i)
3329   {
3330     const TopTools_ListOfShape& aLFIm = myOFImages (i);
3331     //
3332     TopoDS_Compound aCFIm;
3333     aBB.MakeCompound (aCFIm);
3334     //
3335     TopTools_DataMapOfShapeListOfShape aDMEF;
3336     TopTools_ListIteratorOfListOfShape aIt (aLFIm);
3337     for (; aIt.More(); aIt.Next())
3338     {
3339       const TopoDS_Shape& aF = aIt.Value();
3340       aBB.Add (aCFIm, aF);
3341       //
3342       // make a map to use only outer edges
3343       TopExp_Explorer aExp (aF, TopAbs_EDGE);
3344       for (; aExp.More(); aExp.Next())
3345       {
3346         const TopoDS_Shape& aE = aExp.Current();
3347         //
3348         TopTools_ListOfShape* pLF = aDMEF.ChangeSeek (aE);
3349         if (!pLF)
3350         {
3351           pLF = aDMEF.Bound (aE, TopTools_ListOfShape());
3352         }
3353         else
3354         {
3355           // internal edges should not be used
3356           aMEAvoid.Add (aE);
3357         }
3358         AppendToList (*pLF, aF);
3359       }
3360       //
3361       // fill connection map of the vertices of inverted edges to faces
3362       aExp.Init (aF, TopAbs_VERTEX);
3363       for (; aExp.More(); aExp.Next())
3364       {
3365         const TopoDS_Shape& aV = aExp.Current();
3366         //
3367         TopTools_ListOfShape* pLF = aDMVF.ChangeSeek (aV);
3368         if (!pLF)
3369         {
3370           pLF = aDMVF.Bound (aV, TopTools_ListOfShape());
3371         }
3372         AppendToList (*pLF, aF);
3373       }
3374     }
3375     //
3376     // for the splits to be regular they should form only one block
3377     TopTools_ListOfShape aLCBF;
3378     BOPTools_AlgoTools::MakeConnexityBlocks (aCFIm, TopAbs_EDGE, TopAbs_FACE, aLCBF);
3379     if (aLCBF.Extent() == 1)
3380     {
3381       continue;
3382     }
3383     //
3384     // check if the inverted edges create the irregularity
3385     BRepOffset_DataMapOfShapeMapOfShape aDMCBVInverted, aDMCBVAll;
3386     //
3387     TopTools_ListIteratorOfListOfShape aItLCB (aLCBF);
3388     for (; aItLCB.More(); aItLCB.Next())
3389     {
3390       const TopoDS_Shape& aCB = aItLCB.Value();
3391       //
3392       // check if it is possible to remove the block
3393       if (!CheckInvertedBlock (aCB, aLCBF, aDMCBVInverted, aDMCBVAll))
3394       {
3395         // non of the edges in this block should be removed
3396         TopExp::MapShapes (aCB, TopAbs_EDGE, aMEAvoid);
3397         continue;
3398       }
3399     }
3400   }
3401   //
3402   // all edges not included in aMEAvoid can be removed
3403   TopTools_MapOfShape aMERem;
3404   for (Standard_Integer iInverted = 1; iInverted <= myInvertedEdges.Extent(); ++iInverted)
3405   {
3406     const TopoDS_Shape& aE = myInvertedEdges (iInverted);
3407     if (!aMEAvoid.Contains (aE))
3408     {
3409       TopoDS_Iterator aIt (aE);
3410       for (; aIt.More(); aIt.Next())
3411       {
3412         const TopoDS_Shape& aV = aIt.Value();
3413         const TopTools_ListOfShape* pLF = aDMVF.Seek (aV);
3414         if (pLF && (pLF->Extent() > 3))
3415         {
3416           aMERem.Add (aE);
3417           break;
3418         }
3419       }
3420     }
3421   }
3422   //
3423   if (aMERem.IsEmpty())
3424   {
3425     return;
3426   }
3427   //
3428   // all invalid faces containing these edges can be removed
3429   TopTools_IndexedDataMapOfShapeListOfShape aInvFaces;
3430   TopTools_MapOfShape aMFRem;
3431   TopTools_IndexedMapOfShape aMFToUpdate;
3432   aNb = myInvalidFaces.Extent();
3433   for (i = 1; i <= aNb; ++i)
3434   {
3435     const TopoDS_Shape& aF = myInvalidFaces.FindKey (i);
3436     TopTools_ListOfShape& aLFIm = myInvalidFaces (i);
3437     //
3438     TopTools_ListIteratorOfListOfShape aIt (aLFIm);
3439     for (; aIt.More(); )
3440     {
3441       const TopoDS_Shape& aFIm = aIt.Value();
3442       //
3443       // to be removed the face should have at least two not connected
3444       // inverted edges
3445       TopoDS_Compound aCEInv;
3446       aBB.MakeCompound (aCEInv);
3447       TopExp_Explorer aExp (aFIm, TopAbs_EDGE);
3448       for (; aExp.More(); aExp.Next())
3449       {
3450         const TopoDS_Shape& aE = aExp.Current();
3451         if (aMERem.Contains (aE))
3452         {
3453           aBB.Add (aCEInv, aE);
3454         }
3455       }
3456       //
3457       // check connectivity
3458       TopTools_ListOfShape aLCBE;
3459       BOPTools_AlgoTools::MakeConnexityBlocks (aCEInv, TopAbs_VERTEX, TopAbs_EDGE, aLCBE);
3460       //
3461       if (aLCBE.Extent() >= 2)
3462       {
3463         aMFToUpdate.Add (aF);
3464         aMFRem.Add (aFIm);
3465         aLFIm.Remove (aIt);
3466       }
3467       else
3468       {
3469         aIt.Next();
3470       }
3471     }
3472     //
3473     if (aLFIm.Extent())
3474     {
3475       aInvFaces.Add (aF, aLFIm);
3476     }
3477   }
3478   //
3479   if (aMFRem.IsEmpty())
3480   {
3481     return;
3482   }
3483   //
3484   myInvalidFaces = aInvFaces;
3485   // remove from splits
3486   aNb = aMFToUpdate.Extent();
3487   for (i = 1; i <= aNb; ++i)
3488   {
3489     const TopoDS_Shape& aF = aMFToUpdate (i);
3490     TopTools_ListOfShape& aLFIm = myOFImages.ChangeFromKey (aF);
3491     //
3492     TopTools_ListIteratorOfListOfShape aIt (aLFIm);
3493     for (; aIt.More(); )
3494     {
3495       const TopoDS_Shape& aFIm = aIt.Value();
3496       if (aMFRem.Contains (aFIm))
3497       {
3498         TopExp::MapShapes (aFIm, TopAbs_EDGE, theMERemoved);
3499         aLFIm.Remove (aIt);
3500       }
3501       else
3502       {
3503         aIt.Next();
3504       }
3505     }
3506   }
3507 }
3508 
3509 //=======================================================================
3510 //function : RemoveInvalidSplitsFromValid
3511 //purpose  : Removing invalid splits of faces from valid
3512 //=======================================================================
RemoveInvalidSplitsFromValid(const BRepOffset_DataMapOfShapeMapOfShape & theDMFMVIE)3513 void BRepOffset_BuildOffsetFaces::RemoveInvalidSplitsFromValid (const BRepOffset_DataMapOfShapeMapOfShape& theDMFMVIE)
3514 {
3515   // Decide whether to remove the found invalid faces or not.
3516   // The procedure is the following:
3517   // 1. Make connexity blocks from invalid faces;
3518   // 2. Find free edges in this blocks;
3519   // 3. If all free edges are valid for the faces - remove block.
3520   //
3521   TopTools_MapOfShape aMFence, aMFToRem;
3522   TopoDS_Compound aCFInv;
3523   BRep_Builder aBB;
3524   aBB.MakeCompound (aCFInv);
3525   TopTools_ListIteratorOfListOfShape aItLF;
3526   //
3527   // make compound of invalid faces
3528   TopTools_DataMapOfShapeShape aDMIFOF;
3529   Standard_Integer i, aNb = myInvalidFaces.Extent();
3530   for (i = 1; i <= aNb; ++i)
3531   {
3532     const TopoDS_Shape& aF = myInvalidFaces.FindKey (i);
3533     // artificially invalid faces should not be removed
3534     if (myArtInvalidFaces.IsBound (aF))
3535     {
3536       continue;
3537     }
3538     const TopTools_ListOfShape& aLFInv = myInvalidFaces (i);
3539     aItLF.Initialize (aLFInv);
3540     for (; aItLF.More(); aItLF.Next())
3541     {
3542       const TopoDS_Shape& aFIm = aItLF.Value();
3543       if (aMFence.Add (aFIm))
3544       {
3545         aBB.Add (aCFInv, aFIm);
3546         aDMIFOF.Bind (aFIm, aF);
3547       }
3548     }
3549   }
3550   //
3551   // make connexity blocks
3552   TopTools_ListOfShape aLCBInv;
3553   BOPTools_AlgoTools::MakeConnexityBlocks (aCFInv, TopAbs_EDGE, TopAbs_FACE, aLCBInv);
3554   //
3555   // analyze each block
3556   aItLF.Initialize (aLCBInv);
3557   for (; aItLF.More(); aItLF.Next())
3558   {
3559     const TopoDS_Shape& aCB = aItLF.Value();
3560     //
3561     // if connexity block contains only one face - it should be removed;
3562     TopExp_Explorer aExp (aCB, TopAbs_FACE);
3563     aExp.Next();
3564     if (aExp.More())
3565     {
3566       // check if there are valid images left
3567       aExp.Init (aCB, TopAbs_FACE);
3568       for (; aExp.More(); aExp.Next())
3569       {
3570         const TopoDS_Shape& aFIm = aExp.Current();
3571         const TopoDS_Shape& aF = aDMIFOF.Find (aFIm);
3572         //
3573         const TopTools_ListOfShape& aLFIm = myOFImages.FindFromKey (aF);
3574         const TopTools_ListOfShape& aLFInv = myInvalidFaces.FindFromKey (aF);
3575         //
3576         if (aLFIm.Extent() == aLFInv.Extent())
3577         {
3578           break;
3579         }
3580       }
3581     }
3582     //
3583     if (!aExp.More())
3584     {
3585       aExp.Init (aCB, TopAbs_FACE);
3586       for (; aExp.More(); aExp.Next())
3587       {
3588         const TopoDS_Shape& aF = aExp.Current();
3589         aMFToRem.Add (aF);
3590       }
3591       continue;
3592     }
3593     //
3594     // remove faces connected by inverted edges
3595     TopTools_IndexedDataMapOfShapeListOfShape aDMEF;
3596     TopExp::MapShapesAndAncestors (aCB, TopAbs_EDGE, TopAbs_FACE, aDMEF);
3597     //
3598     TopTools_DataMapOfShapeListOfShape aDMFF;
3599     aExp.Init (aCB, TopAbs_FACE);
3600     for (; aExp.More(); aExp.Next())
3601     {
3602       const TopoDS_Shape& aFCB = aExp.Current();
3603       const TopoDS_Shape& aF = aDMIFOF.Find (aFCB);
3604       TopTools_ListOfShape* pList = aDMFF.ChangeSeek (aF);
3605       if (!pList)
3606         pList = aDMFF.Bound (aF, TopTools_ListOfShape());
3607       pList->Append (aFCB);
3608     }
3609 
3610     for (TopTools_DataMapOfShapeListOfShape::Iterator itM (aDMFF); itM.More(); itM.Next())
3611     {
3612       const TopoDS_Shape& aF = itM.Key();
3613       const TopTools_MapOfShape* pValidInverted = theDMFMVIE.Seek (aF);
3614 
3615       // either remove all of these faces or none.
3616       const TopTools_ListOfShape& aLFCB = itM.Value();
3617       TopTools_ListOfShape::Iterator itL (aLFCB);
3618       for (; itL.More(); itL.Next())
3619       {
3620         const TopoDS_Shape& aFCB = itL.Value();
3621         TopExp_Explorer aExpE (aFCB, TopAbs_EDGE);
3622         for (; aExpE.More(); aExpE.Next())
3623         {
3624           const TopoDS_Shape& aECB = aExpE.Current();
3625           if (pValidInverted && pValidInverted->Contains (aECB))
3626             break;
3627           if (aDMEF.FindFromKey (aECB).Extent() > 1)
3628           {
3629             if (!myInvertedEdges.Contains (aECB))
3630               break;
3631           }
3632         }
3633         if (!aExpE.More())
3634           // if one removed - remove all
3635           break;
3636       }
3637       if (itL.More())
3638       {
3639         for (itL.Initialize (aLFCB); itL.More(); itL.Next())
3640         {
3641           aMFToRem.Add (itL.Value());
3642         }
3643       }
3644     }
3645   }
3646   //
3647   if (aMFToRem.Extent())
3648   {
3649     // remove invalid faces from images
3650     aNb = myInvalidFaces.Extent();
3651     for (i = 1; i <= aNb; ++i)
3652     {
3653       const TopoDS_Shape& aF = myInvalidFaces.FindKey (i);
3654       TopTools_ListOfShape& aLFImages = myOFImages.ChangeFromKey (aF);
3655       aItLF.Initialize (aLFImages);
3656       for (; aItLF.More();)
3657       {
3658         const TopoDS_Shape& aFIm = aItLF.Value();
3659         if (aMFToRem.Contains (aFIm))
3660         {
3661           aLFImages.Remove (aItLF);
3662         }
3663         else
3664         {
3665           aItLF.Next();
3666         }
3667       }
3668     }
3669   }
3670 }
3671 
3672 namespace {
3673   //=======================================================================
3674   //function : buildPairs
3675   //purpose  : builds pairs of shapes
3676   //=======================================================================
buildPairs(const TopTools_IndexedMapOfShape & theSMap,BRepOffset_DataMapOfShapeMapOfShape & theIntPairs)3677   static void buildPairs (const TopTools_IndexedMapOfShape& theSMap,
3678                           BRepOffset_DataMapOfShapeMapOfShape& theIntPairs)
3679   {
3680     const Standard_Integer aNbS = theSMap.Extent();
3681     if (aNbS < 2)
3682       return;
3683     for (Standard_Integer it1 = 1; it1 <= aNbS; ++it1)
3684     {
3685       const TopoDS_Shape& aS = theSMap (it1);
3686       if (!theIntPairs.IsBound (aS))
3687         theIntPairs.Bind (aS, TopTools_MapOfShape());
3688     }
3689 
3690     for (Standard_Integer it1 = 1; it1 <= aNbS; ++it1)
3691     {
3692       const TopoDS_Shape& aS1 = theSMap (it1);
3693       TopTools_MapOfShape& aMap1 = theIntPairs (aS1);
3694       for (Standard_Integer it2 = it1 + 1; it2 <= aNbS; ++it2)
3695       {
3696         const TopoDS_Shape& aS2 = theSMap (it2);
3697         aMap1.Add (aS2);
3698         theIntPairs (aS2).Add (aS1);
3699       }
3700     }
3701   }
3702 
3703   //=======================================================================
3704   //function : buildIntersectionPairs
3705   //purpose  : builds intersection pairs
3706   //=======================================================================
buildIntersectionPairs(const TopTools_IndexedDataMapOfShapeListOfShape & myOFImages,const TopTools_IndexedDataMapOfShapeListOfShape & myInvalidFaces,const BOPAlgo_Builder & theBuilder,const TopTools_MapOfShape & theMFRemoved,const TopTools_DataMapOfShapeShape & theFOrigins,NCollection_DataMap<TopoDS_Shape,BRepOffset_DataMapOfShapeMapOfShape,TopTools_ShapeMapHasher> & theIntPairs)3707   static void buildIntersectionPairs (const TopTools_IndexedDataMapOfShapeListOfShape& myOFImages,
3708                                       const TopTools_IndexedDataMapOfShapeListOfShape& myInvalidFaces,
3709                                       const BOPAlgo_Builder& theBuilder,
3710                                       const TopTools_MapOfShape& theMFRemoved,
3711                                       const TopTools_DataMapOfShapeShape& theFOrigins,
3712                                       NCollection_DataMap<TopoDS_Shape,
3713                                       BRepOffset_DataMapOfShapeMapOfShape,
3714                                       TopTools_ShapeMapHasher>& theIntPairs)
3715   {
3716     TopAbs_ShapeEnum aCType = TopAbs_VERTEX;
3717     // Build connection map from vertices to faces
3718     TopTools_IndexedDataMapOfShapeListOfShape aDMVF;
3719     TopExp::MapShapesAndAncestors (theBuilder.Shape(), aCType, TopAbs_FACE, aDMVF);
3720 
3721     const TopTools_DataMapOfShapeListOfShape& anImages = theBuilder.Images();
3722     const TopTools_DataMapOfShapeListOfShape& anOrigins = theBuilder.Origins();
3723 
3724     // Find all faces connected to the not removed faces and build intersection pairs among them.
3725     // For removed faces intersect only those connected to each other.
3726 
3727     for (Standard_Integer iF = 1; iF <= myInvalidFaces.Extent(); ++iF)
3728     {
3729       const TopoDS_Shape& aFInv = myInvalidFaces.FindKey (iF);
3730 
3731       TopoDS_Compound aCF, aCFRem;
3732       BRep_Builder().MakeCompound (aCF);
3733       BRep_Builder().MakeCompound (aCFRem);
3734 
3735       for (Standard_Integer iC = 0; iC < 2; ++iC)
3736       {
3737         const TopTools_ListOfShape& aLF = !iC ? myInvalidFaces (iF) : myOFImages.FindFromKey (aFInv);
3738 
3739         for (TopTools_ListOfShape::Iterator it (aLF); it.More(); it.Next())
3740         {
3741           TopTools_ListOfShape aLFIm;
3742           TakeModified (it.Value(), anImages, aLFIm);
3743 
3744           for (TopTools_ListOfShape::Iterator itIm (aLFIm); itIm.More(); itIm.Next())
3745           {
3746             const TopoDS_Shape& aFIm = itIm.Value();
3747 
3748             if (theMFRemoved.Contains (aFIm))
3749               BRep_Builder().Add (aCFRem, aFIm);
3750             else
3751               BRep_Builder().Add (aCF, aFIm);
3752           }
3753         }
3754       }
3755 
3756       TopTools_ListOfShape aLCB;
3757       BOPTools_AlgoTools::MakeConnexityBlocks (aCF, TopAbs_EDGE, TopAbs_FACE, aLCB);
3758 
3759       if (aLCB.IsEmpty())
3760         continue;
3761 
3762       BRepOffset_DataMapOfShapeMapOfShape* pFInterMap =
3763         theIntPairs.Bound (aFInv, BRepOffset_DataMapOfShapeMapOfShape());
3764 
3765       // build pairs for not removed faces
3766       for (TopTools_ListOfShape::Iterator itCB (aLCB); itCB.More(); itCB.Next())
3767       {
3768         const TopoDS_Shape& aCB = itCB.Value();
3769 
3770         TopTools_IndexedMapOfShape aMFInter;
3771         for (TopExp_Explorer exp (aCB, aCType); exp.More(); exp.Next())
3772         {
3773           const TopoDS_Shape& aCS = exp.Current();
3774           const TopTools_ListOfShape* pLFV = aDMVF.Seek (aCS);
3775           if (!pLFV)
3776             continue;
3777 
3778           for (TopTools_ListOfShape::Iterator itFV (*pLFV); itFV.More(); itFV.Next())
3779           {
3780             const TopoDS_Shape& aFConnected = itFV.Value();
3781 
3782             TopTools_ListOfShape aLFOr;
3783             TakeModified (aFConnected, anOrigins, aLFOr);
3784             for (TopTools_ListOfShape::Iterator itOr (aLFOr); itOr.More(); itOr.Next())
3785             {
3786               const TopoDS_Shape* pFOr = theFOrigins.Seek (itOr.Value());
3787               if (pFOr)
3788                 aMFInter.Add (*pFOr);
3789             }
3790           }
3791         }
3792 
3793         // build intersection pairs
3794         buildPairs (aMFInter, *pFInterMap);
3795       }
3796 
3797       aLCB.Clear();
3798       BOPTools_AlgoTools::MakeConnexityBlocks (aCFRem, TopAbs_EDGE, TopAbs_FACE, aLCB);
3799 
3800       if (aLCB.IsEmpty())
3801         continue;
3802 
3803       for (TopTools_ListOfShape::Iterator itCB (aLCB); itCB.More(); itCB.Next())
3804       {
3805         const TopoDS_Shape& aCB = itCB.Value();
3806 
3807         TopTools_IndexedDataMapOfShapeListOfShape aDMEF;
3808         for (TopExp_Explorer exp (aCB, aCType); exp.More(); exp.Next())
3809         {
3810           const TopoDS_Shape& aCS = exp.Current();
3811           const TopTools_ListOfShape* pLFV = aDMVF.Seek (aCS);
3812           if (!pLFV)
3813             continue;
3814 
3815           for (TopTools_ListOfShape::Iterator itFV (*pLFV); itFV.More(); itFV.Next())
3816           {
3817             const TopoDS_Shape& aFConnected = itFV.Value();
3818             TopExp::MapShapesAndAncestors (aFConnected, TopAbs_EDGE, TopAbs_FACE, aDMEF);
3819           }
3820         }
3821 
3822         for (Standard_Integer iE = 1; iE <= aDMEF.Extent(); ++iE)
3823         {
3824           const TopTools_ListOfShape& aLFConnected = aDMEF (iE);
3825           if (aLFConnected.Extent() < 2)
3826             continue;
3827 
3828           TopTools_IndexedMapOfShape aMFInter;
3829           for (TopTools_ListOfShape::Iterator itLF (aLFConnected); itLF.More(); itLF.Next())
3830           {
3831             const TopoDS_Shape& aFConnected = itLF.Value();
3832 
3833             TopTools_ListOfShape aLFOr;
3834             TakeModified (aFConnected, anOrigins, aLFOr);
3835             for (TopTools_ListOfShape::Iterator itOr (aLFOr); itOr.More(); itOr.Next())
3836             {
3837               const TopoDS_Shape* pFOr = theFOrigins.Seek (itOr.Value());
3838               if (pFOr)
3839                 aMFInter.Add (*pFOr);
3840             }
3841           }
3842 
3843           buildPairs (aMFInter, *pFInterMap);
3844         }
3845       }
3846     }
3847   }
3848 
3849 }
3850 
3851 //=======================================================================
3852 //function : RemoveInsideFaces
3853 //purpose  : Looking for the inside faces that can be safely removed
3854 //=======================================================================
RemoveInsideFaces(const TopTools_ListOfShape & theInvertedFaces,const TopTools_IndexedMapOfShape & theMFToCheckInt,const TopTools_IndexedMapOfShape & theMFInvInHole,const TopoDS_Shape & theFHoles,TopTools_IndexedMapOfShape & theMERemoved,TopTools_IndexedMapOfShape & theMEInside,const Message_ProgressRange & theRange)3855 void BRepOffset_BuildOffsetFaces::RemoveInsideFaces (const TopTools_ListOfShape& theInvertedFaces,
3856                                                      const TopTools_IndexedMapOfShape& theMFToCheckInt,
3857                                                      const TopTools_IndexedMapOfShape& theMFInvInHole,
3858                                                      const TopoDS_Shape& theFHoles,
3859                                                      TopTools_IndexedMapOfShape& theMERemoved,
3860                                                      TopTools_IndexedMapOfShape& theMEInside,
3861                                                      const Message_ProgressRange& theRange)
3862 {
3863   TopTools_ListOfShape aLS;
3864   TopTools_MapOfShape aMFence;
3865   TopTools_IndexedMapOfShape aMFInv;
3866   TopTools_ListIteratorOfListOfShape aItLF;
3867   TopTools_DataMapOfShapeShape aDMFImF;
3868   //
3869   Message_ProgressScope aPS (theRange, "Looking for inside faces", 10);
3870   Standard_Integer i, aNb = myOFImages.Extent();
3871   for (i = 1; i <= aNb; ++i)
3872   {
3873     if (!aPS.More())
3874     {
3875       return;
3876     }
3877     const TopoDS_Shape& aF = myOFImages.FindKey (i);
3878     // to avoid intersection of the splits of the same
3879     // offset faces among themselves make compound of the
3880     // splits and use it as one argument
3881     TopoDS_Compound aCFImi;
3882     BRep_Builder().MakeCompound (aCFImi);
3883     //
3884     for (Standard_Integer j = 0; j < 2; ++j)
3885     {
3886       const TopTools_ListOfShape* pLFSp = !j ? myInvalidFaces.Seek (aF) : &myOFImages (i);
3887       if (!pLFSp)
3888       {
3889         continue;
3890       }
3891       //
3892       aItLF.Initialize (*pLFSp);
3893       for (; aItLF.More(); aItLF.Next())
3894       {
3895         const TopoDS_Shape& aFIm = aItLF.Value();
3896         if (aMFence.Add (aFIm))
3897         {
3898           BRep_Builder().Add (aCFImi, aFIm);
3899           aDMFImF.Bind (aFIm, aF);
3900           if (!j)
3901           {
3902             aMFInv.Add (aFIm);
3903           }
3904         }
3905       }
3906     }
3907     //
3908     aLS.Append (aCFImi);
3909   }
3910   //
3911   // to make the solids more complete add for intersection also the faces
3912   // consisting only of invalid edges and not included into splits
3913   aNb = theMFToCheckInt.Extent();
3914   for (i = 1; i <= aNb; ++i)
3915   {
3916     const TopoDS_Shape& aFSp = theMFToCheckInt (i);
3917     if (aMFence.Add (aFSp))
3918     {
3919       aLS.Append (aFSp);
3920     }
3921   }
3922   //
3923   BOPAlgo_MakerVolume aMV;
3924   aMV.SetArguments (aLS);
3925   aMV.SetIntersect (Standard_True);
3926   aMV.Perform (aPS.Next (9));
3927   if (aMV.HasErrors())
3928     return;
3929 
3930   //
3931   // get shapes connection for using in the rebuilding process
3932   // for the cases in which some of the intersection left undetected
3933   ShapesConnections (aDMFImF, aMV);
3934   //
3935   // find faces to remove
3936   const TopoDS_Shape& aSols = aMV.Shape();
3937   //
3938   TopTools_IndexedDataMapOfShapeListOfShape aDMFS;
3939   TopExp::MapShapesAndAncestors (aSols, TopAbs_FACE, TopAbs_SOLID, aDMFS);
3940   //
3941   aNb = aDMFS.Extent();
3942   if (!aNb)
3943   {
3944     return;
3945   }
3946   //
3947   // To use the created solids for classifications, firstly, it is necessary
3948   // to check them on validity - the created solids should be complete,
3949   // i.e. all faces should be included.
3950   //
3951   TopTools_MapOfShape aMFToRem;
3952   // Check completeness
3953   if (aMV.HasDeleted())
3954   {
3955     TopTools_IndexedMapOfShape aMEHoles;
3956     TopExp::MapShapes (theFHoles, TopAbs_EDGE, aMEHoles);
3957 
3958     // Map edges of the solids to check the connectivity
3959     // of the removed invalid splits
3960     TopTools_IndexedMapOfShape aMESols;
3961     TopExp::MapShapes (aSols, TopAbs_EDGE, aMESols);
3962 
3963     // perform additional check on faces
3964     aNb = myOFImages.Extent();
3965     for (i = 1; i <= aNb; ++i)
3966     {
3967       if (!aPS.More())
3968       {
3969         return;
3970       }
3971       const TopTools_ListOfShape& aLFIm = myOFImages (i);
3972       if (aLFIm.IsEmpty())
3973       {
3974         continue;
3975       }
3976 
3977       const TopoDS_Shape& aF = myOFImages.FindKey (i);
3978       Standard_Boolean bInvalid = myInvalidFaces.Contains (aF);
3979       // For invalid faces it is allowed to be at least connected
3980       // to the solids, otherwise the solids are considered as broken
3981       Standard_Boolean bConnected = Standard_False;
3982 
3983       Standard_Boolean bFaceKept = Standard_False;
3984       aItLF.Initialize (aLFIm);
3985       for (; aItLF.More(); aItLF.Next())
3986       {
3987         const TopoDS_Shape& aFIm = aItLF.Value();
3988         if (!aMV.IsDeleted (aFIm))
3989         {
3990           bFaceKept = Standard_True;
3991           continue;
3992         }
3993         //
3994         TopExp_Explorer aExpE (aFIm, TopAbs_EDGE);
3995         for (; aExpE.More(); aExpE.Next())
3996         {
3997           if (aMEHoles.Contains (aExpE.Current()))
3998           {
3999             bFaceKept = Standard_True;
4000             aMFToRem.Add (aFIm);
4001             break;
4002           }
4003           if (!bFaceKept && bInvalid && !bConnected)
4004             bConnected = aMESols.Contains (aExpE.Current());
4005         }
4006       }
4007       //
4008       if (!bFaceKept && !bConnected)
4009       {
4010         return;
4011       }
4012     }
4013   }
4014   //
4015   TopTools_IndexedMapOfShape aMEBoundary;
4016   aNb = aDMFS.Extent();
4017   for (i = 1; i <= aNb; ++i)
4018   {
4019     const TopoDS_Shape& aFIm = aDMFS.FindKey (i);
4020     const TopTools_ListOfShape& aLSol = aDMFS (i);
4021     if (aLSol.Extent() > 1)
4022     {
4023       aMFToRem.Add (aFIm);
4024     }
4025     else if (aFIm.Orientation() != TopAbs_INTERNAL)
4026     {
4027       TopExp::MapShapes (aFIm, TopAbs_EDGE, aMEBoundary);
4028     }
4029   }
4030 
4031   // Tool for getting the splits of faces
4032   const TopTools_DataMapOfShapeListOfShape& aMVIms = aMV.Images();
4033 
4034   // update invalid faces with images
4035   aNb = aMFInv.Extent();
4036   for (i = 1; i <= aNb; ++i)
4037   {
4038     const TopoDS_Shape& aFInv = aMFInv (i);
4039     TakeModified (aFInv, aMVIms, aMFInv);
4040   }
4041 
4042   // Take into account the faces invalid by inverted edges
4043   for (TopTools_ListOfShape::Iterator itLF (theInvertedFaces); itLF.More(); itLF.Next())
4044     TakeModified (itLF.Value(), aMVIms, aMFInv);
4045 
4046   // check if the invalid faces inside the holes are really invalid:
4047   // check its normal direction - if it has changed relatively the
4048   // original face the offset face is invalid and should be kept for rebuilding
4049   Standard_Integer aNbFH = theMFInvInHole.Extent();
4050   for (i = 1; i <= aNbFH; ++i)
4051   {
4052     if (!aPS.More())
4053     {
4054       return;
4055     }
4056     const TopoDS_Shape& aFInv = theMFInvInHole (i);
4057     TopTools_ListOfShape aLFInvIm = aMV.Modified (aFInv);
4058     if (aLFInvIm.IsEmpty())
4059     {
4060       aLFInvIm.Append (aFInv);
4061     }
4062     //
4063     const TopoDS_Shape* pFOffset = aDMFImF.Seek (aFInv);
4064     if (!pFOffset)
4065     {
4066       continue;
4067     }
4068     TopTools_ListIteratorOfListOfShape aItLFInv (aLFInvIm);
4069     for (; aItLFInv.More(); aItLFInv.Next())
4070     {
4071       const TopoDS_Shape& aFInvIm = aItLFInv.Value();
4072       const TopTools_ListOfShape* pLSols = aDMFS.Seek (aFInvIm);
4073       if (!pLSols || pLSols->Extent() != 1)
4074       {
4075         continue;
4076       }
4077       //
4078       const TopoDS_Shape& aFSol = pLSols->First();
4079       //
4080       TopoDS_Shape aFx;
4081       if (!FindShape (aFInvIm, aFSol, NULL, aFx))
4082       {
4083         continue;
4084       }
4085       //
4086       if (BRepOffset_Tool::CheckPlanesNormals (TopoDS::Face (aFx), TopoDS::Face (*pFOffset)))
4087       {
4088         // the normal direction has not changed, thus the face can be removed
4089         aMFToRem.Add (aFInvIm);
4090       }
4091     }
4092   }
4093   //
4094   TopoDS_Compound aSolids;
4095   BRep_Builder().MakeCompound (aSolids);
4096   TopTools_MapOfShape aMFKeep;
4097   //
4098   TopExp_Explorer aExpS (aSols, TopAbs_SOLID);
4099   for (; aExpS.More(); aExpS.Next())
4100   {
4101     if (!aPS.More())
4102     {
4103       return;
4104     }
4105     const TopoDS_Shape& aSol = aExpS.Current();
4106     //
4107     Standard_Boolean bAllInv (Standard_True), bAllRemoved (Standard_True);
4108 
4109     for (TopExp_Explorer aExpF (aSol, TopAbs_FACE); aExpF.More(); aExpF.Next())
4110     {
4111       const TopoDS_Shape& aFS = aExpF.Current();
4112       //
4113       if (aFS.Orientation() == TopAbs_INTERNAL)
4114       {
4115         aMFToRem.Add (aFS);
4116         continue;
4117       }
4118 
4119       if (aMFToRem.Contains (aFS))
4120         continue;
4121 
4122       bAllRemoved = false;
4123       bAllInv &= aMFInv.Contains (aFS);
4124     }
4125     //
4126     if (bAllInv && !bAllRemoved)
4127     {
4128       // remove invalid faces but keep those that have already been marked for removal
4129       TopExp_Explorer aExpF (aSol, TopAbs_FACE);
4130       for (; aExpF.More(); aExpF.Next())
4131       {
4132         const TopoDS_Shape& aFS = aExpF.Current();
4133         //
4134         if (aMFToRem.Contains (aFS))
4135         {
4136           if (!aMFKeep.Add (aFS))
4137           {
4138             aMFKeep.Remove (aFS);
4139           }
4140         }
4141         else
4142         {
4143           aMFToRem.Add (aFS);
4144         }
4145       }
4146     }
4147     else
4148     {
4149       BRep_Builder().Add (aSolids, aSol);
4150       mySolids = aSolids;
4151     }
4152   }
4153   //
4154   TopTools_MapIteratorOfMapOfShape aItM (aMFKeep);
4155   for (; aItM.More(); aItM.Next())
4156   {
4157     aMFToRem.Remove (aItM.Value());
4158   }
4159 
4160   // Remove the invalid hanging parts external to the solids
4161   RemoveHangingParts (aMV, aDMFImF, aMFInv, aMFToRem);
4162 
4163   // Remove newly found internal and hanging faces
4164   RemoveValidSplits (aMFToRem, aMV, theMERemoved);
4165   RemoveInvalidSplits (aMFToRem, aMV, theMERemoved);
4166   //
4167   // Get inside faces from the removed ones comparing them with boundary edges
4168   aNb = theMERemoved.Extent();
4169   for (i = 1; i <= aNb; ++i)
4170   {
4171     const TopoDS_Shape& aE = theMERemoved (i);
4172     if (!aMEBoundary.Contains (aE))
4173     {
4174       theMEInside.Add (aE);
4175     }
4176   }
4177 
4178   // build all possible intersection pairs basing on the intersection results
4179   // taking into account removed faces.
4180   if (aMFToRem.Extent())
4181     buildIntersectionPairs (myOFImages, myInvalidFaces, aMV, aMFToRem, aDMFImF, myIntersectionPairs);
4182 }
4183 
4184 //=======================================================================
4185 //function : ShapesConnections
4186 //purpose  : Looking for the connections between faces not to miss
4187 //           some necessary intersection
4188 //=======================================================================
ShapesConnections(const TopTools_DataMapOfShapeShape & theDMFOr,BOPAlgo_Builder & theBuilder)4189 void BRepOffset_BuildOffsetFaces::ShapesConnections (const TopTools_DataMapOfShapeShape& theDMFOr,
4190                                                      BOPAlgo_Builder& theBuilder)
4191 {
4192   // update invalid edges with images and keep connection to original edge
4193   TopTools_DataMapOfShapeListOfShape aDMEOr;
4194   Standard_Integer aNb = myInvalidEdges.Extent();
4195   for (Standard_Integer i = 1; i <= aNb; ++i)
4196   {
4197     const TopoDS_Shape& aEInv = myInvalidEdges (i);
4198     const TopTools_ListOfShape& aLEIm = theBuilder.Modified (aEInv);
4199     if (aLEIm.IsEmpty())
4200     {
4201       aDMEOr.Bound (aEInv, TopTools_ListOfShape())->Append (aEInv);
4202       continue;
4203     }
4204     //
4205     TopTools_ListIteratorOfListOfShape aItLEIm (aLEIm);
4206     for (; aItLEIm.More(); aItLEIm.Next())
4207     {
4208       const TopoDS_Shape& aEIm = aItLEIm.Value();
4209       //
4210       TopTools_ListOfShape* pLEOr = aDMEOr.ChangeSeek (aEIm);
4211       if (!pLEOr)
4212       {
4213         pLEOr = aDMEOr.Bound (aEIm, TopTools_ListOfShape());
4214       }
4215       AppendToList (*pLEOr, aEInv);
4216     }
4217   }
4218   //
4219   // get shapes connections for using in the rebuilding process
4220   const BOPDS_PDS& pDS = theBuilder.PDS();
4221   // analyze all Face/Face intersections
4222   const BOPDS_VectorOfInterfFF& aFFs = pDS->InterfFF();
4223   Standard_Integer iInt, aNbFF = aFFs.Length();
4224   for (iInt = 0; iInt < aNbFF; ++iInt)
4225   {
4226     const BOPDS_InterfFF& aFF = aFFs (iInt);
4227     const BOPDS_VectorOfCurve& aVNC = aFF.Curves();
4228     Standard_Integer aNbC = aVNC.Length();
4229     if (!aNbC)
4230     {
4231       continue;
4232     }
4233     //
4234     const TopoDS_Shape& aFIm1 = pDS->Shape (aFF.Index1());
4235     const TopoDS_Shape& aFIm2 = pDS->Shape (aFF.Index2());
4236     //
4237     const TopoDS_Shape* pF1 = theDMFOr.Seek (aFIm1);
4238     const TopoDS_Shape* pF2 = theDMFOr.Seek (aFIm2);
4239     //
4240     if (!pF1 || !pF2)
4241     {
4242       continue;
4243     }
4244     //
4245     if (pF1->IsSame (*pF2))
4246     {
4247       continue;
4248     }
4249     //
4250     Standard_Boolean bInv1 = myInvalidFaces.Contains (*pF1);
4251     Standard_Boolean bInv2 = myInvalidFaces.Contains (*pF2);
4252     //
4253     if (!bInv1 && !bInv2)
4254     {
4255       continue;
4256     }
4257     //
4258     // check if it is real Face/Face intersection
4259     TopTools_MapOfShape aMEInt;
4260     for (Standard_Integer iC = 0; iC < aNbC; ++iC)
4261     {
4262       const BOPDS_Curve& aNC = aVNC (iC);
4263       const BOPDS_ListOfPaveBlock& aLPB = aNC.PaveBlocks();
4264       BOPDS_ListIteratorOfListOfPaveBlock aItLPB (aLPB);
4265       for (; aItLPB.More(); aItLPB.Next())
4266       {
4267         const Handle(BOPDS_PaveBlock)& aPB = aItLPB.Value();
4268         Standard_Integer nEInt;
4269         if (aPB->HasEdge (nEInt))
4270         {
4271           const TopoDS_Shape& aEInt = pDS->Shape (nEInt);
4272           aMEInt.Add (aEInt);
4273         }
4274       }
4275     }
4276     //
4277     if (aMEInt.IsEmpty())
4278     {
4279       continue;
4280     }
4281     //
4282     // check if invalid edges of the face are in the same splits with intersection edges
4283     for (Standard_Integer i = 0; i < 2; ++i)
4284     {
4285       if ((!i && !bInv1) || (i && !bInv2))
4286       {
4287         continue;
4288       }
4289       //
4290       const TopoDS_Shape& aF = !i ? *pF1 : *pF2;
4291       const TopoDS_Shape& aFOp = !i ? *pF2 : *pF1;
4292       const TopoDS_Shape& aFIm = !i ? aFIm1 : aFIm2;
4293       //
4294       Standard_Boolean bFound = Standard_False;
4295       //
4296       TopTools_ListOfShape aLFIm = theBuilder.Modified (aFIm);
4297       if (aLFIm.IsEmpty())
4298       {
4299         aLFIm.Append (aFIm);
4300       }
4301       //
4302       TopTools_ListIteratorOfListOfShape aItLFIm (aLFIm);
4303       for (; aItLFIm.More(); aItLFIm.Next())
4304       {
4305         const TopoDS_Shape& aFImIm = aItLFIm.Value();
4306         //
4307         Standard_Boolean bInv (Standard_False), bInt (Standard_False);
4308         TopExp_Explorer aExpE (aFImIm, TopAbs_EDGE);
4309         for (; aExpE.More(); aExpE.Next())
4310         {
4311           const TopoDS_Shape& aE = aExpE.Current();
4312           if (!bInv)
4313           {
4314             bInv = aDMEOr.IsBound (aE);
4315           }
4316           if (!bInt)
4317           {
4318             bInt = aMEInt.Contains (aE);
4319           }
4320           if (bInv && bInt)
4321           {
4322             break;
4323           }
4324         }
4325         //
4326         if (!bInt || !bInv)
4327         {
4328           continue;
4329         }
4330         //
4331         bFound = Standard_True;
4332         //
4333         // append opposite face to all invalid edges in the split
4334         aExpE.Init (aFImIm, TopAbs_EDGE);
4335         for (; aExpE.More(); aExpE.Next())
4336         {
4337           const TopoDS_Shape& aE = aExpE.Current();
4338           const TopTools_ListOfShape* pLEOr = aDMEOr.Seek (aE);
4339           if (!pLEOr)
4340           {
4341             continue;
4342           }
4343           //
4344           TopTools_ListIteratorOfListOfShape aItLE (*pLEOr);
4345           for (; aItLE.More(); aItLE.Next())
4346           {
4347             const TopoDS_Shape& aEOr = aItLE.Value();
4348             TopTools_ListOfShape* pLFE = mySSInterfs.ChangeSeek (aEOr);
4349             if (!pLFE)
4350             {
4351               pLFE = mySSInterfs.Bound (aEOr, TopTools_ListOfShape());
4352             }
4353             AppendToList (*pLFE, aFOp);
4354           }
4355         }
4356       }
4357       if (bFound)
4358       {
4359         // save connection between offset faces
4360         TopTools_ListOfShape* pLF = mySSInterfs.ChangeSeek (aF);
4361         if (!pLF)
4362         {
4363           pLF = mySSInterfs.Bound (aF, TopTools_ListOfShape());
4364         }
4365         AppendToList (*pLF, aFOp);
4366       }
4367     }
4368   }
4369 }
4370 
4371 //=======================================================================
4372 //function : RemoveHangingParts
4373 //purpose  : Remove isolated invalid hanging parts
4374 //=======================================================================
RemoveHangingParts(const BOPAlgo_MakerVolume & theMV,const TopTools_DataMapOfShapeShape & theDMFImF,const TopTools_IndexedMapOfShape & theMFInv,TopTools_MapOfShape & theMFToRem)4375 void BRepOffset_BuildOffsetFaces::RemoveHangingParts (const BOPAlgo_MakerVolume& theMV,
4376                                                       const TopTools_DataMapOfShapeShape& theDMFImF,
4377                                                       const TopTools_IndexedMapOfShape& theMFInv,
4378                                                       TopTools_MapOfShape& theMFToRem)
4379 {
4380   // Map the faces of the result solids to filter them from avoided faces
4381   TopTools_IndexedMapOfShape aMFS;
4382   TopExp::MapShapes (theMV.Shape(), TopAbs_FACE, aMFS);
4383 
4384   BRep_Builder aBB;
4385   // Build compound of all faces not included into solids
4386   TopoDS_Compound aCFHangs;
4387   aBB.MakeCompound (aCFHangs);
4388 
4389   // Tool for getting the splits of faces
4390   const TopTools_DataMapOfShapeListOfShape& aMVIms = theMV.Images();
4391 
4392   TopTools_ListIteratorOfListOfShape aItLArgs (theMV.Arguments());
4393   for (; aItLArgs.More(); aItLArgs.Next())
4394   {
4395     TopExp_Explorer anExpF (aItLArgs.Value(), TopAbs_FACE);
4396     for (; anExpF.More(); anExpF.Next())
4397     {
4398       const TopoDS_Shape& aF = anExpF.Current();
4399       TakeModified (aF, aMVIms, aCFHangs, &aMFS);
4400     }
4401   }
4402 
4403   // Make connexity blocks of all hanging parts and check that they are isolated
4404   TopTools_ListOfShape aLCBHangs;
4405   BOPTools_AlgoTools::MakeConnexityBlocks (aCFHangs, TopAbs_EDGE, TopAbs_FACE, aLCBHangs);
4406   if (aLCBHangs.IsEmpty())
4407     return;
4408 
4409   // To be removed, the block should contain invalid splits of offset faces and should
4410   // meet one of the following conditions:
4411   // 1. The block should not be connected to any invalid parts (Faces or Edges)
4412   //    contained in solids;
4413   // 2. The block should be isolated from other faces, i.e. it should consist of
4414   //    the splits of the single offset face.
4415 
4416   // Map the edges and vertices of the result solids to check connectivity
4417   // of the hanging blocks to invalid parts contained in solids
4418   TopTools_IndexedDataMapOfShapeListOfShape aDMEF, aDMVE;
4419   TopExp::MapShapesAndAncestors (theMV.Shape(), TopAbs_EDGE, TopAbs_FACE, aDMEF);
4420   TopExp::MapShapesAndAncestors (theMV.Shape(), TopAbs_VERTEX, TopAbs_EDGE, aDMVE);
4421 
4422   // Update invalid edges with intersection results
4423   TopTools_MapOfShape aMEInv;
4424   Standard_Integer i, aNbE = myInvalidEdges.Extent();
4425   for (i = 1; i <= aNbE; ++i)
4426     TakeModified (myInvalidEdges (i), aMVIms, aMEInv);
4427 
4428   // Update inverted edges with intersection results
4429   TopTools_MapOfShape aMEInverted;
4430   for (Standard_Integer iInv = 1; iInv <= myInvertedEdges.Extent(); ++iInv)
4431     TakeModified (myInvertedEdges (iInv), aMVIms, aMEInverted);
4432 
4433   // Tool for getting the origins of the splits
4434   const TopTools_DataMapOfShapeListOfShape& aMVOrs = theMV.Origins();
4435 
4436   // Find hanging blocks to remove
4437   TopTools_ListOfShape aBlocksToRemove;
4438 
4439   TopTools_ListIteratorOfListOfShape aItLCBH (aLCBHangs);
4440   for (; aItLCBH.More(); aItLCBH.Next())
4441   {
4442     const TopoDS_Shape& aCBH = aItLCBH.Value();
4443 
4444     // Remove the block containing the inverted edges
4445     Standard_Boolean bHasInverted = Standard_False;
4446     TopExp_Explorer anExpE (aCBH, TopAbs_EDGE);
4447     for (; anExpE.More() && !bHasInverted; anExpE.Next())
4448     {
4449       const TopoDS_Shape& aE = anExpE.Current();
4450       bHasInverted = !aDMEF.Contains (aE) &&
4451         aMEInverted.Contains (aE);
4452     }
4453 
4454     if (bHasInverted)
4455     {
4456       aBlocksToRemove.Append (aCBH);
4457       continue;
4458     }
4459 
4460     // Check the block to contain invalid split
4461     Standard_Boolean bHasInvalidFace = Standard_False;
4462     // Check connectivity to invalid parts
4463     Standard_Boolean bIsConnected = Standard_False;
4464     TopTools_IndexedMapOfShape aBlockME;
4465     TopExp::MapShapes (aCBH, TopAbs_EDGE, aBlockME);
4466     // Map to collect all original faces
4467     TopTools_MapOfShape aMOffsetF;
4468 
4469     TopExp_Explorer anExpF (aCBH, TopAbs_FACE);
4470     for (; anExpF.More(); anExpF.Next())
4471     {
4472       const TopoDS_Shape& aF = anExpF.Current();
4473       // Check block to contain invalid face
4474       if (!bHasInvalidFace)
4475         bHasInvalidFace = theMFInv.Contains (aF);
4476 
4477       // Check block for connectivity to invalid parts
4478       if (!bIsConnected)
4479       {
4480         // check edges
4481         anExpE.Init (aF, TopAbs_EDGE);
4482         for (; anExpE.More() && !bIsConnected; anExpE.Next())
4483         {
4484           const TopoDS_Shape& aE = anExpE.Current();
4485           const TopTools_ListOfShape* pLF = aDMEF.Seek (aE);
4486           if (pLF)
4487           {
4488             TopTools_ListIteratorOfListOfShape aItLF (*pLF);
4489             for (; aItLF.More() && !bIsConnected; aItLF.Next())
4490               bIsConnected = theMFInv.Contains (aItLF.Value());
4491           }
4492         }
4493         // check vertices
4494         if (!bIsConnected)
4495         {
4496           TopExp_Explorer anExpV (aF, TopAbs_VERTEX);
4497           for (; anExpV.More() && !bIsConnected; anExpV.Next())
4498           {
4499             const TopoDS_Shape& aV = anExpV.Current();
4500             const TopTools_ListOfShape* pLE = aDMVE.Seek (aV);
4501             if (pLE)
4502             {
4503               TopTools_ListIteratorOfListOfShape aItLE (*pLE);
4504               for (; aItLE.More() && !bIsConnected; aItLE.Next())
4505                 bIsConnected = !aBlockME.Contains (aItLE.Value()) &&
4506                 aMEInv.Contains (aItLE.Value());
4507             }
4508           }
4509         }
4510       }
4511 
4512       // Check block to be isolated
4513       const TopTools_ListOfShape* pLFOr = aMVOrs.Seek (aF);
4514       if (pLFOr)
4515       {
4516         TopTools_ListIteratorOfListOfShape aItLFOr (*pLFOr);
4517         for (; aItLFOr.More(); aItLFOr.Next())
4518         {
4519           const TopoDS_Shape* pFOffset = theDMFImF.Seek (aItLFOr.Value());
4520           if (pFOffset)
4521             aMOffsetF.Add (*pFOffset);
4522         }
4523       }
4524       else
4525       {
4526         const TopoDS_Shape* pFOffset = theDMFImF.Seek (aF);
4527         if (pFOffset)
4528           aMOffsetF.Add (*pFOffset);
4529       }
4530     }
4531 
4532     Standard_Boolean bRemove = bHasInvalidFace &&
4533       (!bIsConnected || aMOffsetF.Extent() == 1);
4534 
4535     if (bRemove)
4536       aBlocksToRemove.Append (aCBH);
4537   }
4538 
4539   // remove the invalidated blocks
4540   aItLCBH.Initialize (aBlocksToRemove);
4541   for (; aItLCBH.More(); aItLCBH.Next())
4542   {
4543     const TopoDS_Shape& aCBH = aItLCBH.Value();
4544     TopExp_Explorer anExpF (aCBH, TopAbs_FACE);
4545     for (; anExpF.More(); anExpF.Next())
4546       theMFToRem.Add (anExpF.Current());
4547   }
4548 }
4549 
4550 //=======================================================================
4551 //function : RemoveValidSplits
4552 //purpose  : Removing valid splits according to results of intersection
4553 //=======================================================================
RemoveValidSplits(const TopTools_MapOfShape & theSpRem,BOPAlgo_Builder & theGF,TopTools_IndexedMapOfShape & theMERemoved)4554 void BRepOffset_BuildOffsetFaces::RemoveValidSplits (const TopTools_MapOfShape& theSpRem,
4555                                                      BOPAlgo_Builder& theGF,
4556                                                      TopTools_IndexedMapOfShape& theMERemoved)
4557 {
4558   Standard_Integer i, aNb = myOFImages.Extent();
4559   if (!aNb)
4560   {
4561     return;
4562   }
4563   //
4564   for (i = 1; i <= aNb; ++i)
4565   {
4566     TopTools_ListOfShape& aLSIm = myOFImages (i);
4567     TopTools_ListIteratorOfListOfShape aIt (aLSIm);
4568     for (; aIt.More(); )
4569     {
4570       const TopoDS_Shape& aSIm = aIt.Value();
4571       if (theSpRem.Contains (aSIm))
4572       {
4573         TopExp::MapShapes (aSIm, TopAbs_EDGE, theMERemoved);
4574         aLSIm.Remove (aIt);
4575         continue;
4576       }
4577       //
4578       // check if all its images are have to be removed
4579       const TopTools_ListOfShape& aLSImIm = theGF.Modified (aSIm);
4580       if (aLSImIm.Extent())
4581       {
4582         Standard_Boolean bAllRem = Standard_True;
4583         TopTools_ListIteratorOfListOfShape aIt1 (aLSImIm);
4584         for (; aIt1.More(); aIt1.Next())
4585         {
4586           const TopoDS_Shape& aSImIm = aIt1.Value();
4587           if (theSpRem.Contains (aSImIm))
4588           {
4589             TopExp::MapShapes (aSImIm, TopAbs_EDGE, theMERemoved);
4590           }
4591           else
4592           {
4593             bAllRem = Standard_False;
4594           }
4595         }
4596         //
4597         if (bAllRem)
4598         {
4599           TopExp::MapShapes (aSIm, TopAbs_EDGE, theMERemoved);
4600           aLSIm.Remove (aIt);
4601           continue;
4602         }
4603       }
4604       aIt.Next();
4605     }
4606   }
4607 }
4608 
4609 //=======================================================================
4610 //function : RemoveInvalidSplits
4611 //purpose  : Removing invalid splits according to the results of intersection
4612 //=======================================================================
RemoveInvalidSplits(const TopTools_MapOfShape & theSpRem,BOPAlgo_Builder & theGF,TopTools_IndexedMapOfShape & theMERemoved)4613 void BRepOffset_BuildOffsetFaces::RemoveInvalidSplits (const TopTools_MapOfShape& theSpRem,
4614                                                        BOPAlgo_Builder& theGF,
4615                                                        TopTools_IndexedMapOfShape& theMERemoved)
4616 {
4617   Standard_Integer i, aNb = myInvalidFaces.Extent();
4618   if (!aNb)
4619   {
4620     return;
4621   }
4622   //
4623   for (i = 1; i <= aNb; ++i)
4624   {
4625     const TopoDS_Shape& aS = myInvalidFaces.FindKey (i);
4626     Standard_Boolean bArt = myArtInvalidFaces.IsBound (aS);
4627     //
4628     TopTools_ListOfShape& aLSIm = myInvalidFaces (i);
4629     TopTools_ListIteratorOfListOfShape aIt (aLSIm);
4630     for (; aIt.More();)
4631     {
4632       const TopoDS_Shape& aSIm = aIt.Value();
4633       if (theSpRem.Contains (aSIm))
4634       {
4635         TopExp::MapShapes (aSIm, TopAbs_EDGE, theMERemoved);
4636         aLSIm.Remove (aIt);
4637         continue;
4638       }
4639       //
4640       // check if all its images are have to be removed
4641       const TopTools_ListOfShape& aLSImIm = theGF.Modified (aSIm);
4642       if (aLSImIm.IsEmpty())
4643       {
4644         aIt.Next();
4645         continue;
4646       }
4647       //
4648       Standard_Boolean bAllRem = Standard_True;
4649       TopTools_IndexedMapOfShape aMERemoved;
4650       TopTools_ListIteratorOfListOfShape aIt1 (aLSImIm);
4651       for (; aIt1.More(); aIt1.Next())
4652       {
4653         const TopoDS_Shape& aSImIm = aIt1.Value();
4654         if (theSpRem.Contains (aSImIm))
4655         {
4656           TopExp::MapShapes (aSImIm, TopAbs_EDGE, aMERemoved);
4657         }
4658         else
4659         {
4660           bAllRem = Standard_False;
4661         }
4662       }
4663       //
4664       if (bAllRem)
4665       {
4666         aLSIm.Remove (aIt);
4667         continue;
4668       }
4669       //
4670       if (bArt)
4671       {
4672         aIt.Next();
4673         continue;
4674       }
4675       //
4676       // remove the face from invalid if all invalid edges of this face
4677       // have been marked for removal
4678       TopExp_Explorer aExpE (aSIm, TopAbs_EDGE);
4679       for (; aExpE.More(); aExpE.Next())
4680       {
4681         const TopoDS_Shape& aEInv = aExpE.Current();
4682         if (myInvalidEdges.Contains (aEInv) && !aMERemoved.Contains (aEInv))
4683         {
4684           break;
4685         }
4686       }
4687       if (!aExpE.More())
4688       {
4689         TopExp::MapShapes (aSIm, TopAbs_EDGE, theMERemoved);
4690         aLSIm.Remove (aIt);
4691       }
4692       else
4693       {
4694         aIt.Next();
4695       }
4696     }
4697   }
4698 }
4699 
4700 //=======================================================================
4701 //function : FilterEdgesImages
4702 //purpose  : Updating the maps of images and origins of the offset edges
4703 //=======================================================================
FilterEdgesImages(const TopoDS_Shape & theS)4704 void BRepOffset_BuildOffsetFaces::FilterEdgesImages (const TopoDS_Shape& theS)
4705 {
4706   // map edges
4707   TopTools_IndexedMapOfShape aME;
4708   TopExp::MapShapes (theS, TopAbs_EDGE, aME);
4709   //
4710   myOEOrigins.Clear();
4711   TopTools_DataMapIteratorOfDataMapOfShapeListOfShape aItDM (myOEImages);
4712   for (; aItDM.More(); aItDM.Next())
4713   {
4714     const TopoDS_Shape& aE = aItDM.Key();
4715     TopTools_ListOfShape& aLEIm = aItDM.ChangeValue();
4716     //
4717     TopTools_ListIteratorOfListOfShape aIt (aLEIm);
4718     for (; aIt.More(); )
4719     {
4720       const TopoDS_Shape& aEIm = aIt.Value();
4721       // filter images
4722       if (!aME.Contains (aEIm))
4723       {
4724         // remove the image
4725         // edges with no images left should be kept in the map
4726         // to avoid their usage when building the splits of faces
4727         aLEIm.Remove (aIt);
4728         continue;
4729       }
4730       //
4731       // save origins
4732       if (myOEOrigins.IsBound (aEIm))
4733       {
4734         AppendToList (myOEOrigins.ChangeFind (aEIm), aE);
4735       }
4736       else
4737       {
4738         TopTools_ListOfShape aLOr;
4739         aLOr.Append (aE);
4740         myOEOrigins.Bind (aEIm, aLOr);
4741       }
4742       //
4743       aIt.Next();
4744     }
4745   }
4746 }
4747 
4748 //=======================================================================
4749 //function : FilterInvalidFaces
4750 //purpose  : Filtering of the invalid faces
4751 //=======================================================================
FilterInvalidFaces(const TopTools_IndexedDataMapOfShapeListOfShape & theDMEF,const TopTools_IndexedMapOfShape & theMERemoved)4752 void BRepOffset_BuildOffsetFaces::FilterInvalidFaces (const TopTools_IndexedDataMapOfShapeListOfShape& theDMEF,
4753                                                       const TopTools_IndexedMapOfShape& theMERemoved)
4754 {
4755   //
4756   // filter invalid faces, considering faces having only valid
4757   // images left with non-free edges as valid
4758   // do not remove invalid faces if it creates free edges
4759   //
4760   TopTools_IndexedDataMapOfShapeListOfShape aReallyInvFaces;
4761   // Edge-Face connexity map of all splits, both invalid and valid
4762   TopTools_IndexedDataMapOfShapeListOfShape aDMEFAll;
4763   TopTools_ListIteratorOfListOfShape aItLF;
4764   //
4765   const Standard_Integer aNb = myInvalidFaces.Extent();
4766   for (Standard_Integer i = 1; i <= aNb; ++i)
4767   {
4768     const TopoDS_Shape& aF = myInvalidFaces.FindKey (i);
4769     const TopTools_ListOfShape& aLFInv = myInvalidFaces (i);
4770     //
4771     if (myArtInvalidFaces.IsBound (aF))
4772     {
4773       if (aLFInv.IsEmpty())
4774       {
4775         myArtInvalidFaces.UnBind (aF);
4776       }
4777       else
4778       {
4779         aReallyInvFaces.Add (aF, aLFInv);
4780       }
4781       continue;
4782     }
4783     //
4784     if (aLFInv.IsEmpty())
4785     {
4786       continue;
4787     }
4788     //
4789     TopTools_ListOfShape& aLFIm = myOFImages.ChangeFromKey (aF);
4790     Standard_Boolean bInvalid = aLFIm.IsEmpty();
4791     //
4792     if (!bInvalid)
4793     {
4794       // check two lists on common splits
4795       aItLF.Initialize (aLFInv);
4796       for (; aItLF.More(); aItLF.Next())
4797       {
4798         const TopoDS_Shape& aFInv = aItLF.Value();
4799         //
4800         TopTools_ListIteratorOfListOfShape aItLFIm (aLFIm);
4801         for (; aItLFIm.More(); aItLFIm.Next())
4802         {
4803           const TopoDS_Shape& aFIm = aItLFIm.Value();
4804           //
4805           if (aFInv.IsSame (aFIm))
4806           {
4807             break;
4808           }
4809         }
4810         //
4811         if (aItLFIm.More())
4812         {
4813           break;
4814         }
4815       }
4816       //
4817       bInvalid = aItLF.More();
4818     }
4819     //
4820     if (!bInvalid)
4821     {
4822       // check for free edges
4823       for (Standard_Integer j = 0; !bInvalid && j < 2; ++j)
4824       {
4825         const TopTools_ListOfShape& aLI = !j ? aLFIm : aLFInv;
4826         aItLF.Initialize (aLI);
4827         for (; aItLF.More(); aItLF.Next())
4828         {
4829           const TopoDS_Shape& aFIm = aItLF.Value();
4830           //
4831           TopExp_Explorer aExp (aFIm, TopAbs_EDGE);
4832           for (; aExp.More(); aExp.Next())
4833           {
4834             const TopoDS_Shape& aE = aExp.Current();
4835             if (!theMERemoved.Contains (aE))
4836             {
4837               const TopTools_ListOfShape* pLEF = theDMEF.Seek (aE);
4838               if (pLEF && pLEF->Extent() == 1)
4839               {
4840                 break;
4841               }
4842             }
4843           }
4844           //
4845           if (aExp.More())
4846           {
4847             break;
4848           }
4849         }
4850         bInvalid = aItLF.More();
4851       }
4852     }
4853     if (bInvalid)
4854     {
4855       if (aDMEFAll.IsEmpty())
4856       {
4857         aDMEFAll = theDMEF;
4858         for (Standard_Integer iF = 1; iF <= aNb; ++iF)
4859           for (TopTools_ListOfShape::Iterator itLFInv (myInvalidFaces (iF)); itLFInv.More(); itLFInv.Next())
4860             TopExp::MapShapesAndAncestors (itLFInv.Value(), TopAbs_EDGE, TopAbs_FACE, aDMEFAll);
4861       }
4862 
4863       TopTools_MapOfShape aLocalSplits;
4864       for (Standard_Integer j = 0; j < 2; ++j)
4865         for (aItLF.Initialize ((!j ? aLFIm : aLFInv)); aItLF.More(); aItLF.Next())
4866           aLocalSplits.Add (aItLF.Value());
4867 
4868       // Check if all invalid edges are located inside the split and do not touch
4869       // any other faces both invalid and valid
4870       aItLF.Initialize (aLFInv);
4871       for (; aItLF.More(); aItLF.Next())
4872       {
4873         const TopoDS_Shape& aFIm = aItLF.Value();
4874         TopExp_Explorer aExp (aFIm, TopAbs_EDGE);
4875         for (; aExp.More(); aExp.Next())
4876         {
4877           const TopoDS_Shape& aE = aExp.Current();
4878           if (myInvalidEdges.Contains (aE) && !theMERemoved.Contains (aE))
4879           {
4880             const TopTools_ListOfShape& aLF = aDMEFAll.FindFromKey (aE);
4881             TopTools_ListOfShape::Iterator itLF (aLF);
4882             for (; itLF.More(); itLF.Next())
4883             {
4884               if (!aLocalSplits.Contains (itLF.Value()))
4885                 break;
4886             }
4887             if (itLF.More())
4888               break;
4889           }
4890         }
4891         if (aExp.More())
4892           break;
4893       }
4894       bInvalid = aItLF.More();
4895       if (!bInvalid)
4896       {
4897         aItLF.Initialize (aLFInv);
4898         for (; aItLF.More(); aItLF.Next())
4899           AppendToList (aLFIm, aItLF.Value());
4900       }
4901     }
4902     //
4903     if (bInvalid)
4904     {
4905       aReallyInvFaces.Add (aF, aLFInv);
4906     }
4907   }
4908   //
4909   myInvalidFaces = aReallyInvFaces;
4910 }
4911 
4912 //=======================================================================
4913 //function : CheckEdgesCreatedByVertex
4914 //purpose  : Checks additionally the unchecked edges originated from vertices
4915 //=======================================================================
CheckEdgesCreatedByVertex()4916 void BRepOffset_BuildOffsetFaces::CheckEdgesCreatedByVertex()
4917 {
4918   // Mark the unchecked edges contained in invalid faces as invalid
4919   const Standard_Integer aNbF = myInvalidFaces.Extent();
4920   for (Standard_Integer i = 1; i <= aNbF; ++i)
4921   {
4922     const TopoDS_Shape& aF = myInvalidFaces.FindKey (i);
4923     if (myArtInvalidFaces.IsBound (aF))
4924       continue;
4925 
4926     const TopTools_ListOfShape& aLFIm = myInvalidFaces (i);
4927     for (TopTools_ListOfShape::Iterator it (aLFIm); it.More(); it.Next())
4928     {
4929       const TopoDS_Shape& aFIm = it.Value();
4930       for (TopExp_Explorer expE (aFIm, TopAbs_EDGE); expE.More(); expE.Next())
4931       {
4932         const TopoDS_Shape& aE = expE.Current();
4933         if (myInvalidEdges.Contains (aE)
4934             || myValidEdges.Contains (aE))
4935         {
4936           continue;
4937         }
4938 
4939         // check if this edges is not created from vertex and mark it as invalid
4940         const TopTools_ListOfShape* pLEOr = myEdgesOrigins->Seek (aE);
4941         if (!pLEOr)
4942           continue;
4943         TopTools_ListOfShape::Iterator itLEO (*pLEOr);
4944         for (; itLEO.More(); itLEO.Next())
4945         {
4946           if (itLEO.Value().ShapeType() != TopAbs_VERTEX)
4947             break;
4948         }
4949         if (!itLEO.More())
4950         {
4951           myInvalidEdges.Add (aE);
4952         }
4953       }
4954     }
4955   }
4956 }
4957 
4958 //=======================================================================
4959 //function : FilterInvalidEdges
4960 //purpose  : Filtering the invalid edges according to currently invalid faces
4961 //=======================================================================
FilterInvalidEdges(const BRepOffset_DataMapOfShapeIndexedMapOfShape & theDMFMIE,const TopTools_IndexedMapOfShape & theMERemoved)4962 void BRepOffset_BuildOffsetFaces::FilterInvalidEdges (const BRepOffset_DataMapOfShapeIndexedMapOfShape& theDMFMIE,
4963                                                       const TopTools_IndexedMapOfShape& theMERemoved)
4964 {
4965   TopoDS_Compound aCEInv;
4966   TopTools_IndexedMapOfShape aMEInv;
4967   BRep_Builder aBB;
4968   aBB.MakeCompound (aCEInv);
4969   TopTools_ListIteratorOfListOfShape aItLF;
4970   //
4971   Standard_Integer i, aNb = myInvalidFaces.Extent();
4972   for (i = 1; i <= aNb; ++i)
4973   {
4974     const TopTools_ListOfShape& aLFInv = myInvalidFaces (i);
4975     aItLF.Initialize (aLFInv);
4976     for (; aItLF.More(); aItLF.Next())
4977     {
4978       const TopoDS_Shape& aFIm = aItLF.Value();
4979       TopExp::MapShapes (aFIm, TopAbs_EDGE, aMEInv);
4980       //
4981       TopExp_Explorer aExpE (aFIm, TopAbs_EDGE);
4982       for (; aExpE.More(); aExpE.Next())
4983       {
4984         const TopoDS_Shape& aE = aExpE.Current();
4985         if (myInvalidEdges.Contains (aE))
4986         {
4987           aBB.Add (aCEInv, aE);
4988         }
4989       }
4990     }
4991   }
4992   //
4993   // remove edges which have been marked for removal
4994   TopTools_IndexedMapOfShape aMEInvToAvoid;
4995   TopTools_ListOfShape aLCBE;
4996   BOPTools_AlgoTools::MakeConnexityBlocks (aCEInv, TopAbs_VERTEX, TopAbs_EDGE, aLCBE);
4997   //
4998   TopTools_ListIteratorOfListOfShape aItLCBE (aLCBE);
4999   for (; aItLCBE.More(); aItLCBE.Next())
5000   {
5001     const TopoDS_Shape& aCBE = aItLCBE.Value();
5002     TopExp_Explorer aExpCB (aCBE, TopAbs_EDGE);
5003     for (; aExpCB.More(); aExpCB.Next())
5004     {
5005       const TopoDS_Shape& aE = aExpCB.Current();
5006       if (!theMERemoved.Contains (aE))
5007       {
5008         break;
5009       }
5010     }
5011     //
5012     if (!aExpCB.More())
5013     {
5014       TopExp::MapShapes (aCBE, TopAbs_EDGE, aMEInvToAvoid);
5015     }
5016   }
5017   //
5018   TopTools_IndexedMapOfShape aReallyInvEdges;
5019   //
5020   aNb = myInvalidFaces.Extent();
5021   for (i = 1; i <= aNb; ++i)
5022   {
5023     const TopoDS_Shape& aF = myInvalidFaces.FindKey (i);
5024     if (myArtInvalidFaces.IsBound (aF))
5025     {
5026       const TopTools_IndexedMapOfShape& aMIE = theDMFMIE.Find (aF);
5027       const Standard_Integer aNbIE = aMIE.Extent();
5028       for (Standard_Integer iE = 1; iE <= aNbIE; ++iE)
5029       {
5030         const TopoDS_Shape& aE = aMIE (iE);
5031         if (aMEInv.Contains (aE) && !aMEInvToAvoid.Contains (aE))
5032         {
5033           aReallyInvEdges.Add (aE);
5034         }
5035       }
5036     }
5037     else
5038     {
5039       const TopTools_ListOfShape& aLFInv = myInvalidFaces (i);
5040       aItLF.Initialize (aLFInv);
5041       for (; aItLF.More(); aItLF.Next())
5042       {
5043         const TopoDS_Shape& aFIm = aItLF.Value();
5044         TopExp_Explorer aExpE (aFIm, TopAbs_EDGE);
5045         for (; aExpE.More(); aExpE.Next())
5046         {
5047           const TopoDS_Shape& aE = aExpE.Current();
5048           if (myInvalidEdges.Contains (aE) && !aMEInvToAvoid.Contains (aE))
5049           {
5050             aReallyInvEdges.Add (aE);
5051           }
5052         }
5053       }
5054     }
5055   }
5056   //
5057   myInvalidEdges = aReallyInvEdges;
5058 }
5059 
5060 //=======================================================================
5061 //function : FindFacesToRebuild
5062 //purpose  : Looking for the faces that have to be rebuilt:
5063 //           1. Faces close to invalidity
5064 //           2. Faces containing some invalid parts
5065 //=======================================================================
FindFacesToRebuild()5066 void BRepOffset_BuildOffsetFaces::FindFacesToRebuild()
5067 {
5068   Standard_Integer i, aNb = myOFImages.Extent();
5069   if (!aNb)
5070   {
5071     return;
5072   }
5073   //
5074   Standard_Boolean bRebuild;
5075   TopTools_ListIteratorOfListOfShape aItLF;
5076   TopTools_ListOfShape aLEValid;
5077   TopTools_MapOfShape aMFence, aMEReb, aMFReb;
5078   TopExp_Explorer aExp;
5079   //
5080   TopTools_DataMapOfShapeListOfShape aDMFLV;
5081   // get edges from invalid faces
5082   aNb = myInvalidFaces.Extent();
5083   for (i = 1; i <= aNb; i++)
5084   {
5085     const TopoDS_Shape& aF = myInvalidFaces.FindKey (i);
5086     aMFence.Clear();
5087     TopTools_ListOfShape aLVAvoid;
5088     const TopTools_ListOfShape& aLFIm = myInvalidFaces (i);
5089     aItLF.Initialize (aLFIm);
5090     for (; aItLF.More(); aItLF.Next())
5091     {
5092       const TopoDS_Shape& aFIm = aItLF.Value();
5093       aExp.Init (aFIm, TopAbs_EDGE);
5094       for (; aExp.More(); aExp.Next())
5095       {
5096         const TopoDS_Shape& aE = aExp.Current();
5097         aMEReb.Add (aE);
5098         if (myInvalidEdges.Contains (aE))
5099         {
5100           TopExp_Explorer aExpV (aE, TopAbs_VERTEX);
5101           for (; aExpV.More(); aExpV.Next())
5102           {
5103             const TopoDS_Shape& aV = aExpV.Current();
5104             if (aMFence.Add (aV))
5105             {
5106               aLVAvoid.Append (aV);
5107               aMEReb.Add (aV);
5108             }
5109           }
5110         }
5111       }
5112     }
5113     //
5114     if (aLVAvoid.Extent())
5115     {
5116       aDMFLV.Bind (aF, aLVAvoid);
5117     }
5118     //
5119     const TopTools_ListOfShape* pLF = mySSInterfs.Seek (aF);
5120     if (pLF)
5121     {
5122       TopTools_ListIteratorOfListOfShape aItLFE (*pLF);
5123       for (; aItLFE.More(); aItLFE.Next())
5124       {
5125         const TopoDS_Shape& aFE = aItLFE.Value();
5126         aMFReb.Add (aFE);
5127       }
5128     }
5129   }
5130   //
5131   // get face to rebuild
5132   aNb = myOFImages.Extent();
5133   for (i = 1; i <= aNb; i++)
5134   {
5135     const TopoDS_Shape& aF = myOFImages.FindKey (i);
5136     const TopTools_ListOfShape& aLFIm = myOFImages (i);
5137     TopTools_MapOfShape aMVAvoid;
5138     if (aDMFLV.IsBound (aF))
5139     {
5140       const TopTools_ListOfShape& aLVAvoid = aDMFLV.Find (aF);
5141       TopTools_ListIteratorOfListOfShape aItLV (aLVAvoid);
5142       for (; aItLV.More(); aItLV.Next())
5143       {
5144         const TopoDS_Shape& aV = aItLV.Value();
5145         aMVAvoid.Add (aV);
5146       }
5147     }
5148     //
5149     bRebuild = aMFReb.Contains (aF);
5150     aLEValid.Clear();
5151     aMFence.Clear();
5152     //
5153     aItLF.Initialize (aLFIm);
5154     for (; aItLF.More(); aItLF.Next())
5155     {
5156       const TopoDS_Shape& aFIm = aItLF.Value();
5157       aExp.Init (aFIm, TopAbs_EDGE);
5158       for (; aExp.More(); aExp.Next())
5159       {
5160         const TopoDS_Edge& anEIm = TopoDS::Edge (aExp.Current());
5161         if (!myInvalidEdges.Contains (anEIm))
5162         {
5163           if (aMFence.Add (anEIm))
5164           {
5165             aLEValid.Append (anEIm);
5166           }
5167         }
5168         //
5169         if (!bRebuild)
5170         {
5171           bRebuild = aMEReb.Contains (anEIm);
5172         }
5173         //
5174         if (!bRebuild)
5175         {
5176           // check vertices
5177           TopExp_Explorer aExpV (anEIm, TopAbs_VERTEX);
5178           for (; aExpV.More() && !bRebuild; aExpV.Next())
5179           {
5180             const TopoDS_Shape& aV = aExpV.Current();
5181             if (!aMVAvoid.Contains (aV))
5182             {
5183               bRebuild = aMEReb.Contains (aV);
5184             }
5185           }
5186         }
5187       }
5188     }
5189     //
5190     if (!bRebuild)
5191     {
5192       bRebuild = aLFIm.Extent() && myInvalidFaces.Contains (aF);
5193       if (bRebuild)
5194       {
5195         myFSelfRebAvoid.Add (aF);
5196       }
5197     }
5198     //
5199     if (bRebuild)
5200     {
5201       myFacesToRebuild.Add (aF, aLEValid);
5202     }
5203   }
5204 }
5205 
5206 //=======================================================================
5207 //function : IntersectFaces
5208 //purpose  : Intersection of the faces that should be rebuild to resolve all invalidities
5209 //=======================================================================
IntersectFaces(TopTools_MapOfShape & theVertsToAvoid,const Message_ProgressRange & theRange)5210 void BRepOffset_BuildOffsetFaces::IntersectFaces (TopTools_MapOfShape& theVertsToAvoid,
5211                                                   const Message_ProgressRange& theRange)
5212 {
5213   Standard_Integer aNbFR = myFacesToRebuild.Extent();
5214   if (!aNbFR)
5215   {
5216     return;
5217   }
5218 
5219   Message_ProgressScope aPSOuter (theRange, "Rebuilding invalid faces", 10);
5220   //
5221   Standard_Integer i, j, k, aNbInv;
5222   TopTools_ListIteratorOfListOfShape aItLF, aItLE;
5223   //
5224   // get vertices from invalid edges
5225   TopTools_MapOfShape aMVInv, aMVInvAll;
5226   aNbInv = myInvalidEdges.Extent();
5227   for (i = 1; i <= aNbInv; ++i)
5228   {
5229     const TopoDS_Shape& aEInv = myInvalidEdges (i);
5230     Standard_Boolean bValid = myValidEdges.Contains (aEInv);
5231     for (TopExp_Explorer aExp (aEInv, TopAbs_VERTEX); aExp.More(); aExp.Next())
5232     {
5233       const TopoDS_Shape& aV = aExp.Current();
5234       aMVInvAll.Add (aV);
5235       if (!bValid)
5236       {
5237         aMVInv.Add (aV);
5238       }
5239     }
5240   }
5241   //
5242   Standard_Boolean bLookVertToAvoid = (aMVInv.Extent() > 0);
5243   //
5244   TopTools_DataMapOfShapeListOfShape aDMSF, aMDone, aMEInfETrim, aDMVEFull;
5245   TopTools_IndexedDataMapOfShapeListOfShape aFLE, aDMEFInv;
5246   //
5247   // Add all faces to rebuild to outgoing map <aFLE>,
5248   // plus link edges and vertices to the faces to
5249   // define intersection faces
5250   PrepareFacesForIntersection (bLookVertToAvoid, aFLE, aMDone, aDMSF, aMEInfETrim, aDMVEFull, aDMEFInv);
5251 
5252   // Find vertices to avoid while trimming the edges.
5253   // These vertices are taken from the invalid edges common between
5254   // splits of different invalid, but not artificially, faces.
5255   // Additional condition for these vertices is that all
5256   // edges adjacent to this vertex must be either invalid
5257   // or contained in invalid faces
5258   TopTools_MapOfShape aMVRInv = theVertsToAvoid;
5259   FindVerticesToAvoid (aDMEFInv, aDMVEFull, aMVRInv);
5260   //
5261   aPSOuter.Next();
5262   if (!aPSOuter.More())
5263   {
5264     return;
5265   }
5266 
5267   // The faces should be intersected selectively -
5268   // intersect only faces neighboring to the same invalid face
5269   // and connected to its invalid edges;
5270   // when dealing with artificially invalid faces for intersection to be
5271   // complete we need to use not only invalid edges, but also the
5272   // edges connected to invalid ones
5273 
5274   // find blocks of artificially invalid faces
5275   TopTools_DataMapOfShapeShape aDMFImF;
5276   TopoDS_Compound aCFArt;
5277   BRep_Builder().MakeCompound (aCFArt);
5278   TopTools_DataMapIteratorOfDataMapOfShapeShape aItM (myArtInvalidFaces);
5279   for (; aItM.More(); aItM.Next())
5280   {
5281     const TopoDS_Shape& aF = aItM.Key();
5282     const TopTools_ListOfShape& aLFInv = myInvalidFaces.FindFromKey (aF);
5283     aItLF.Initialize (aLFInv);
5284     for (; aItLF.More(); aItLF.Next())
5285     {
5286       BRep_Builder().Add (aCFArt, aItLF.Value());
5287       aDMFImF.Bind (aItLF.Value(), aF);
5288     }
5289   }
5290   //
5291   // make connexity blocks
5292   TopTools_ListOfShape aLCBArt;
5293   BOPTools_AlgoTools::MakeConnexityBlocks (aCFArt, TopAbs_VERTEX, TopAbs_FACE, aLCBArt);
5294   //
5295   // alone edges
5296   TopTools_MapOfShape aMEAlone, aMEInvOnArt;
5297   //
5298   Message_ProgressScope aPSArt (aPSOuter.Next(), NULL, aLCBArt.Extent());
5299   TopTools_ListIteratorOfListOfShape aItLCBArt (aLCBArt);
5300   for (; aItLCBArt.More(); aItLCBArt.Next(), aPSArt.Next())
5301   {
5302     if (!aPSArt.More())
5303     {
5304       return;
5305     }
5306     const TopoDS_Shape& aCB = aItLCBArt.Value();
5307     //
5308     // check if aCB contains splits of only one offset face
5309     TopTools_MapOfShape aMFArt;
5310     TopExp_Explorer aExpF (aCB, TopAbs_FACE);
5311     for (; aExpF.More(); aExpF.Next())
5312     {
5313       aMFArt.Add (aDMFImF.Find (aExpF.Current()));
5314     }
5315     //
5316     Standard_Boolean bAlone = (aMFArt.Extent() == 1);
5317     //
5318     // vertices on invalid edges
5319     TopTools_MapOfShape aMVEInv;
5320     TopTools_MapOfShape aMFence;
5321     // edges that should not be marked as alone - edges having same origins as invalid ones
5322     TopTools_MapOfShape aMEAvoid;
5323     // map to find alone edges by looking for free vertices
5324     TopTools_IndexedDataMapOfShapeListOfShape aDMVEVal;
5325     //
5326     TopExp_Explorer aExpE (aCB, TopAbs_EDGE);
5327     for (; aExpE.More(); aExpE.Next())
5328     {
5329       const TopoDS_Shape& aE = aExpE.Current();
5330       if (myInvalidEdges.Contains (aE))
5331       {
5332         aMEInvOnArt.Add (aE);
5333         for (TopoDS_Iterator aItV (aE); aItV.More(); aItV.Next())
5334         {
5335           aMVEInv.Add (aItV.Value());
5336         }
5337         //
5338         if (bAlone)
5339         {
5340           const TopTools_ListOfShape* pLEOr = myOEOrigins.Seek (aE);
5341           if (pLEOr)
5342           {
5343             TopTools_ListIteratorOfListOfShape aItLEOr (*pLEOr);
5344             for (; aItLEOr.More(); aItLEOr.Next())
5345             {
5346               TopTools_ListIteratorOfListOfShape aItLEIm (myOEImages.Find (aItLEOr.Value()));
5347               for (; aItLEIm.More(); aItLEIm.Next())
5348               {
5349                 aMEAvoid.Add (aItLEIm.Value());
5350               }
5351             }
5352           }
5353         }
5354         continue;
5355       }
5356       //
5357       if (aMFence.Add (aE))
5358       {
5359         TopExp::MapShapesAndAncestors (aE, TopAbs_VERTEX, TopAbs_EDGE, aDMVEVal);
5360       }
5361     }
5362     //
5363     // find edges with free vertices
5364     Standard_Integer aNbV = aDMVEVal.Extent();
5365     for (i = 1; i <= aNbV; ++i)
5366     {
5367       const TopoDS_Shape& aV = aDMVEVal.FindKey (i);
5368       if (!aMVEInv.Contains (aV))
5369       {
5370         continue;
5371       }
5372       //
5373       const TopTools_ListOfShape& aLEV = aDMVEVal (i);
5374       if (aLEV.Extent() > 1)
5375       {
5376         continue;
5377       }
5378       //
5379       const TopoDS_Shape& aE = aLEV.First();
5380       if (aMEAvoid.Contains (aE))
5381       {
5382         continue;
5383       }
5384       //
5385       aMEAlone.Add (aE);
5386       //
5387       // if this alone edge adds nothing to the intersection list
5388       // it means that the origin of this edge has been split and we need to
5389       // add the neighboring images of the same origins
5390       if (aDMSF.Find (aE).Extent() > 1)
5391       {
5392         continue;
5393       }
5394       //
5395       // check also its vertices
5396       TopoDS_Iterator aItE (aE);
5397       for (; aItE.More(); aItE.Next())
5398       {
5399         const TopoDS_Shape& aVE = aItE.Value();
5400         if (aDMSF.Find (aVE).Extent() > 2)
5401         {
5402           break;
5403         }
5404       }
5405       //
5406       if (aItE.More())
5407       {
5408         continue;
5409       }
5410       //
5411       // the edge is useless - look for other images
5412       const TopTools_ListOfShape* pLEOr = myOEOrigins.Seek (aE);
5413       if (!pLEOr)
5414       {
5415         continue;
5416       }
5417       //
5418       TopTools_ListIteratorOfListOfShape aItLEOr (*pLEOr);
5419       for (; aItLEOr.More(); aItLEOr.Next())
5420       {
5421         const TopoDS_Shape& aEOr = aItLEOr.Value();
5422         //
5423         const TopTools_ListOfShape& aLEIm = myOEImages.Find (aEOr);
5424         TopTools_ListIteratorOfListOfShape aItLEIm (aLEIm);
5425         for (; aItLEIm.More(); aItLEIm.Next())
5426         {
5427           const TopoDS_Shape& aEIm = aItLEIm.Value();
5428           //
5429           if (aMFence.Contains (aEIm))
5430           {
5431             aMEAlone.Add (aEIm);
5432           }
5433         }
5434       }
5435     }
5436   }
5437   //
5438   // Get all invalidities from all faces to be used for avoiding
5439   // repeated usage of the common edges
5440   TopTools_MapOfShape aMAllInvs;
5441   aNbInv = myInvalidFaces.Extent();
5442   for (k = 1; k <= aNbInv; ++k)
5443   {
5444     TopTools_ListIteratorOfListOfShape aIt (myInvalidFaces (k));
5445     for (; aIt.More(); aIt.Next())
5446     {
5447       TopExp_Explorer aExp (aIt.Value(), TopAbs_EDGE);
5448       for (; aExp.More(); aExp.Next())
5449       {
5450         const TopoDS_Shape& aE = aExp.Current();
5451         if (myInvalidEdges.Contains (aE) || aMEAlone.Contains (aE))
5452         {
5453           aMAllInvs.Add (aE);
5454           TopoDS_Iterator aItV (aE);
5455           for (; aItV.More(); aItV.Next())
5456           {
5457             aMAllInvs.Add (aItV.Value());
5458           }
5459         }
5460       }
5461     }
5462   }
5463   //
5464   // Bounding vertices of not trimmed edges
5465   TopTools_MapOfShape aMVBounds;
5466   //
5467   TopTools_MapOfShape aMECheckExt;
5468   // Save connections between not trimmed edge and its trimmed parts
5469   TopTools_DataMapOfShapeListOfShape aDMEETrim;
5470   // Splits of the new edges
5471   TopTools_DataMapOfShapeListOfShape aEImages;
5472   BRep_Builder aBB;
5473 
5474   // Keep connection between blocks of invalid edges to the lists of
5475   // found edges to be intersected for its treatment
5476   TopTools_IndexedDataMapOfShapeListOfShape aDMOENEdges;
5477 
5478   aNbInv = myInvalidFaces.Extent();
5479   Message_ProgressScope aPSInter (aPSOuter.Next (5), NULL, aNbInv);
5480   for (k = 1; k <= aNbInv; ++k)
5481   {
5482     if (!aPSInter.More())
5483     {
5484       return;
5485     }
5486     const TopoDS_Shape& aFInv = myInvalidFaces.FindKey (k);
5487     Standard_Boolean bSelfRebAvoid = myFSelfRebAvoid.Contains (aFInv);
5488     const TopTools_ListOfShape& aLFInv = myInvalidFaces (k);
5489     //
5490     TopTools_ListOfShape aLCB;
5491     if (aLFInv.Extent() > 1)
5492     {
5493       // make compound of invalid faces
5494       TopoDS_Compound aCFInv;
5495       aBB.MakeCompound (aCFInv);
5496       //
5497       TopTools_ListIteratorOfListOfShape aIt (aLFInv);
5498       for (; aIt.More(); aIt.Next())
5499       {
5500         const TopoDS_Shape& aFIm = aIt.Value();
5501         aBB.Add (aCFInv, aFIm);
5502       }
5503       //
5504       // make connexity blocks
5505       BOPTools_AlgoTools::MakeConnexityBlocks (aCFInv, TopAbs_EDGE, TopAbs_FACE, aLCB);
5506     }
5507     else
5508     {
5509       aLCB = aLFInv;
5510     }
5511     //
5512     Message_ProgressScope aPSCB (aPSInter.Next(), NULL, aLCB.Extent());
5513     Standard_Boolean bArtificial = myArtInvalidFaces.IsBound (aFInv);
5514     TopTools_ListIteratorOfListOfShape aItLCB (aLCB);
5515     for (; aItLCB.More(); aItLCB.Next())
5516     {
5517       if (!aPSCB.More())
5518       {
5519         return;
5520       }
5521       const TopoDS_Shape& aCBInv = aItLCB.Value();
5522       //
5523       TopTools_MapOfShape aMEFence;
5524       //
5525       TopoDS_Compound aCBE;
5526       aBB.MakeCompound (aCBE);
5527       //
5528       TopExp_Explorer aExp (aCBInv, TopAbs_EDGE);
5529       for (; aExp.More(); aExp.Next())
5530       {
5531         const TopoDS_Shape& aE = aExp.Current();
5532         if (myInvalidEdges.Contains (aE) || (bArtificial && aMEAlone.Contains (aE)))
5533         {
5534           if (aMEFence.Add (aE))
5535           {
5536             aBB.Add (aCBE, aE);
5537           }
5538         }
5539       }
5540       //
5541       // make connexity blocks of edges
5542       TopTools_ListOfShape aLCBE;
5543       BOPTools_AlgoTools::MakeConnexityBlocks (aCBE, TopAbs_VERTEX, TopAbs_EDGE, aLCBE);
5544       //
5545       Message_ProgressScope aPSCBE (aPSCB.Next(), NULL, aLCBE.Extent());
5546       TopTools_ListIteratorOfListOfShape aItLCBE (aLCBE);
5547       for (; aItLCBE.More(); aItLCBE.Next())
5548       {
5549         if (!aPSCBE.More())
5550         {
5551           return;
5552         }
5553         const TopoDS_Shape& aCBELoc = aItLCBE.Value();
5554         //
5555         // map of edges and vertices of processing invalidity
5556         TopTools_IndexedMapOfShape aME;
5557         // map of vertices to trim the new edges
5558         TopTools_IndexedMapOfShape  aMECV;
5559         TopExp::MapShapes (aCBELoc, TopAbs_EDGE, aME);
5560         aMECV = aME;
5561         TopExp::MapShapes (aCBELoc, TopAbs_VERTEX, aME);
5562         //
5563         // Using the map <aME> find chain of faces to be intersected;
5564         //
5565         // faces for intersection
5566         TopTools_IndexedMapOfShape aMFInt;
5567         // additional faces for intersection
5568         TopTools_IndexedMapOfShape aMFIntExt;
5569         // splits of faces for intersection
5570         TopTools_ListOfShape aLFInt;
5571         // faces to avoid intersection
5572         TopTools_IndexedMapOfShape aMFAvoid;
5573         //
5574         FindFacesForIntersection (aFInv, aME, aDMSF, aMVInvAll, bArtificial, aMFAvoid, aMFInt, aMFIntExt, aLFInt);
5575         if (aMFInt.Extent() < 3)
5576         {
5577           // nothing to intersect
5578           aPSCBE.Next();
5579           continue;
5580         }
5581         //
5582         const BRepOffset_DataMapOfShapeMapOfShape* pMFInter = myIntersectionPairs.Seek (aFInv);
5583         // intersect the faces, but do not intersect the invalid ones
5584         // among each other (except for the artificially invalid faces)
5585         TopTools_IndexedMapOfShape aMEToInt;
5586         Standard_Integer aNb = aMFInt.Extent();
5587         Message_ProgressScope aPSIntPair (aPSCBE.Next(), NULL, aNb);
5588         for (i = 1; i <= aNb; ++i, aPSIntPair.Next())
5589         {
5590           if (!aPSIntPair.More())
5591           {
5592             return;
5593           }
5594           const TopoDS_Face& aFi = TopoDS::Face (aMFInt (i));
5595           if (bSelfRebAvoid && aFi.IsSame (aFInv))
5596           {
5597             continue;
5598           }
5599           //
5600           const TopTools_ListOfShape& aLFImi = myOFImages.FindFromKey (aFi);
5601           //
5602           TopTools_ListOfShape& aLFEi = aFLE.ChangeFromKey (aFi);
5603           //
5604           TopTools_ListOfShape& aLFDone = aMDone.ChangeFind (aFi);
5605           //
5606           const TopTools_MapOfShape* pInterFi = !pMFInter ? 0 : pMFInter->Seek (aFi);
5607           if (pMFInter && !pInterFi)
5608             continue;
5609 
5610           for (j = i + 1; j <= aNb; ++j)
5611           {
5612             const TopoDS_Face& aFj = TopoDS::Face (aMFInt (j));
5613             if (bSelfRebAvoid && aFj.IsSame (aFInv))
5614             {
5615               continue;
5616             }
5617             //
5618             if (pInterFi && !pInterFi->Contains (aFj))
5619               continue;
5620 
5621             const TopTools_ListOfShape& aLFImj = myOFImages.FindFromKey (aFj);
5622             //
5623             TopTools_ListOfShape& aLFEj = aFLE.ChangeFromKey (aFj);
5624             //
5625             // if there are some common edges between faces
5626             // we should use these edges and do not intersect again.
5627             TopTools_ListOfShape aLEC;
5628             FindCommonParts (aLFImi, aLFImj, aLEC);
5629             //
5630             if (aLEC.Extent())
5631             {
5632               // no need to intersect if we have common edges between faces
5633               Standard_Boolean bForceUse = aMFIntExt.Contains (aFi) || aMFIntExt.Contains (aFj);
5634               ProcessCommonEdges (aLEC, aME, aMEInfETrim, aMAllInvs, bForceUse, aMECV, aMECheckExt, aDMEETrim, aLFEi, aLFEj, aMEToInt);
5635               continue;
5636             }
5637             //
5638             // check if both these faces are invalid and sharing edges
5639             if (myInvalidFaces.Contains (aFi) && myInvalidFaces.Contains (aFj) &&
5640                 !myArtInvalidFaces.IsBound (aFi) && !myArtInvalidFaces.IsBound (aFj))
5641             {
5642               continue;
5643             }
5644             //
5645             // check if these two faces have already been treated
5646             aItLE.Initialize (aLFDone);
5647             for (; aItLE.More(); aItLE.Next())
5648             {
5649               const TopoDS_Shape& aF = aItLE.Value();
5650               if (aF.IsSame (aFj))
5651               {
5652                 break;
5653               }
5654             }
5655             //
5656             if (aItLE.More())
5657             {
5658               // use intersection line obtained on the previous steps
5659               // plus, find new origins for these lines
5660               UpdateIntersectedFaces (aFInv, aFi, aFj, aLFInv, aLFImi, aLFImj, aLFEi, aLFEj, aMEToInt);
5661               continue;
5662             }
5663             //
5664             if (aMFAvoid.Contains (aFi) || aMFAvoid.Contains (aFj))
5665             {
5666               continue;
5667             }
5668             //
5669             aLFDone.Append (aFj);
5670             aMDone.ChangeFind (aFj).Append (aFi);
5671             //
5672             IntersectFaces (aFInv, aFi, aFj, aLFInv, aLFImi, aLFImj, aLFEi, aLFEj, aMECV, aMEToInt);
5673           }
5674         }
5675         //
5676         // intersect and trim edges for this chain
5677         IntersectAndTrimEdges (aMFInt, aMEToInt, aDMEETrim, aME, aMECV,
5678                                aMVInv, aMVRInv, aMECheckExt, aMVBounds, aEImages);
5679         //
5680         Standard_Integer iE, aNbEToInt = aMEToInt.Extent();
5681         for (iE = 1; iE <= aNbEToInt; ++iE)
5682         {
5683           const TopoDS_Shape& aEInt = aMEToInt (iE);
5684           TopExp_Explorer anExpE (aCBELoc, TopAbs_EDGE);
5685           for (; anExpE.More(); anExpE.Next())
5686           {
5687             const TopoDS_Shape& aE = anExpE.Current();
5688             TopTools_ListOfShape* pLEToInt = aDMOENEdges.ChangeSeek (aE);
5689             if (!pLEToInt)
5690               pLEToInt = &aDMOENEdges (aDMOENEdges.Add (aE, TopTools_ListOfShape()));
5691             AppendToList (*pLEToInt, aEInt);
5692           }
5693         }
5694       }
5695     }
5696   }
5697   //
5698   // filter the obtained edges
5699   UpdateValidEdges (aFLE, aDMOENEdges, aMVBounds, aMEInvOnArt, aMECheckExt,
5700                     theVertsToAvoid, aEImages, aDMEETrim, aPSOuter.Next (3));
5701 }
5702 
5703 //=======================================================================
5704 //function : PrepareFacesForIntersection
5705 //purpose  : Preparation of the maps for analyzing intersections of the faces
5706 //=======================================================================
PrepareFacesForIntersection(const Standard_Boolean theLookVertToAvoid,TopTools_IndexedDataMapOfShapeListOfShape & theFLE,TopTools_DataMapOfShapeListOfShape & theMDone,TopTools_DataMapOfShapeListOfShape & theDMSF,TopTools_DataMapOfShapeListOfShape & theMEInfETrim,TopTools_DataMapOfShapeListOfShape & theDMVEFull,TopTools_IndexedDataMapOfShapeListOfShape & theDMEFInv)5707 void BRepOffset_BuildOffsetFaces::PrepareFacesForIntersection (const Standard_Boolean theLookVertToAvoid,
5708                                                                TopTools_IndexedDataMapOfShapeListOfShape& theFLE,
5709                                                                TopTools_DataMapOfShapeListOfShape& theMDone,
5710                                                                TopTools_DataMapOfShapeListOfShape& theDMSF,
5711                                                                TopTools_DataMapOfShapeListOfShape& theMEInfETrim,
5712                                                                TopTools_DataMapOfShapeListOfShape& theDMVEFull,
5713                                                                TopTools_IndexedDataMapOfShapeListOfShape& theDMEFInv)
5714 {
5715   Standard_Integer i, aNb = myFacesToRebuild.Extent();
5716   for (i = 1; i <= aNb; ++i)
5717   {
5718     const TopoDS_Shape& aF = myFacesToRebuild.FindKey (i);
5719     //
5720     TopTools_ListOfShape aLE;
5721     theFLE.Add (aF, aLE);
5722     theMDone.Bind (aF, aLE);
5723     //
5724     const TopTools_ListOfShape& aLFIm = myOFImages.FindFromKey (aF);
5725     TopTools_ListIteratorOfListOfShape aItLF (aLFIm);
5726     for (; aItLF.More(); aItLF.Next())
5727     {
5728       const TopoDS_Shape& aFIm = aItLF.Value();
5729       TopExp_Explorer aExp (aFIm, TopAbs_EDGE);
5730       for (; aExp.More(); aExp.Next())
5731       {
5732         const TopoDS_Shape& aE = aExp.Current();
5733         // save connection to untrimmed face
5734         TopTools_ListOfShape* pLF = theDMSF.ChangeSeek (aE);
5735         if (!pLF)
5736         {
5737           pLF = theDMSF.Bound (aE, TopTools_ListOfShape());
5738         }
5739         AppendToList (*pLF, aF);
5740         //
5741         // save connection to untrimmed edge
5742         const TopoDS_Shape& aEInf = myETrimEInf->Find (aE);
5743         TopTools_ListOfShape* pLETrim = theMEInfETrim.ChangeSeek (aEInf);
5744         if (!pLETrim)
5745         {
5746           pLETrim = theMEInfETrim.Bound (aEInf, TopTools_ListOfShape());
5747         }
5748         AppendToList (*pLETrim, aE);
5749         //
5750         TopExp_Explorer aExpV (aE, TopAbs_VERTEX);
5751         for (; aExpV.More(); aExpV.Next())
5752         {
5753           const TopoDS_Shape& aV = aExpV.Current();
5754           // save connection to face
5755           TopTools_ListOfShape* pLFV = theDMSF.ChangeSeek (aV);
5756           if (!pLFV)
5757           {
5758             pLFV = theDMSF.Bound (aV, TopTools_ListOfShape());
5759           }
5760           AppendToList (*pLFV, aF);
5761           //
5762           if (theLookVertToAvoid)
5763           {
5764             // save connection to edges
5765             TopTools_ListOfShape* pLEV = theDMVEFull.ChangeSeek (aV);
5766             if (!pLEV)
5767             {
5768               pLEV = theDMVEFull.Bound (aV, TopTools_ListOfShape());
5769             }
5770             AppendToList (*pLEV, aE);
5771           }
5772         }
5773       }
5774     }
5775     //
5776     if (theLookVertToAvoid)
5777     {
5778       // get edges of invalid faces (from invalid splits only)
5779       const TopTools_ListOfShape* pLFInv = myInvalidFaces.Seek (aF);
5780       if (!pLFInv || myArtInvalidFaces.IsBound (aF))
5781       {
5782         continue;
5783       }
5784       //
5785       aItLF.Initialize (*pLFInv);
5786       for (; aItLF.More(); aItLF.Next())
5787       {
5788         const TopoDS_Shape& aFInv = aItLF.Value();
5789         TopExp_Explorer aExp (aFInv, TopAbs_EDGE);
5790         for (; aExp.More(); aExp.Next())
5791         {
5792           const TopoDS_Shape& aE = aExp.Current();
5793           TopTools_ListOfShape* pLF = theDMEFInv.ChangeSeek (aE);
5794           if (!pLF)
5795           {
5796             pLF = &theDMEFInv (theDMEFInv.Add (aE, TopTools_ListOfShape()));
5797           }
5798           AppendToList (*pLF, aF);
5799         }
5800       }
5801     }
5802   }
5803 }
5804 
5805 //=======================================================================
5806 //function : FindVerticesToAvoid
5807 //purpose  : Looking for the invalid vertices
5808 //=======================================================================
FindVerticesToAvoid(const TopTools_IndexedDataMapOfShapeListOfShape & theDMEFInv,const TopTools_DataMapOfShapeListOfShape & theDMVEFull,TopTools_MapOfShape & theMVRInv)5809 void BRepOffset_BuildOffsetFaces::FindVerticesToAvoid (const TopTools_IndexedDataMapOfShapeListOfShape& theDMEFInv,
5810                                                        const TopTools_DataMapOfShapeListOfShape& theDMVEFull,
5811                                                        TopTools_MapOfShape& theMVRInv)
5812 {
5813   TopTools_MapOfShape aMFence;
5814   Standard_Integer i, aNb = theDMEFInv.Extent();
5815   for (i = 1; i <= aNb; ++i)
5816   {
5817     const TopTools_ListOfShape& aLFInv = theDMEFInv (i);
5818     if (aLFInv.Extent() == 1)
5819     {
5820       continue;
5821     }
5822     //
5823     const TopoDS_Shape& aE = theDMEFInv.FindKey (i);
5824     if (!myInvalidEdges.Contains (aE) || myValidEdges.Contains (aE))
5825     {
5826       continue;
5827     }
5828 
5829     if (!aMFence.Add (aE))
5830       continue;
5831 
5832     TopTools_IndexedDataMapOfShapeListOfShape aMVEEdges;
5833     // Do not check the splitting vertices, but check only the ending ones
5834     const TopTools_ListOfShape* pLEOr = myOEOrigins.Seek (aE);
5835     if (pLEOr)
5836     {
5837       TopTools_ListIteratorOfListOfShape aItLEOr (*pLEOr);
5838       for (; aItLEOr.More(); aItLEOr.Next())
5839       {
5840         const TopTools_ListOfShape& aLEIm = myOEImages.Find (aItLEOr.Value());
5841         TopTools_ListIteratorOfListOfShape aItLEIm (aLEIm);
5842         for (; aItLEIm.More(); aItLEIm.Next())
5843         {
5844           aMFence.Add (aItLEIm.Value());
5845           TopExp::MapShapesAndAncestors (aItLEIm.Value(), TopAbs_VERTEX, TopAbs_EDGE, aMVEEdges);
5846         }
5847       }
5848     }
5849     else
5850     {
5851       TopExp::MapShapesAndAncestors (aE, TopAbs_VERTEX, TopAbs_EDGE, aMVEEdges);
5852     }
5853 
5854     Standard_Integer j, aNbV = aMVEEdges.Extent();
5855     for (j = 1; j <= aNbV; ++j)
5856     {
5857       if (aMVEEdges (j).Extent() != 1)
5858         continue;
5859 
5860       const TopoDS_Shape& aV = aMVEEdges.FindKey (j);
5861       if (!aMFence.Add (aV))
5862         continue;
5863       const TopTools_ListOfShape* pLE = theDMVEFull.Seek (aV);
5864       if (!pLE)
5865       {
5866         // isolated vertex
5867         theMVRInv.Add (aV);
5868         continue;
5869       }
5870       //
5871       // If all edges sharing the vertex are either invalid or
5872       // the vertex is connected to at least two inverted edges
5873       // mark the vertex to be avoided in the new splits
5874       Standard_Integer iNbEInverted = 0;
5875       Standard_Boolean bAllEdgesInv = Standard_True;
5876       TopTools_ListIteratorOfListOfShape aItLE (*pLE);
5877       for (; aItLE.More(); aItLE.Next())
5878       {
5879         const TopoDS_Shape& aEV = aItLE.Value();
5880 
5881         if (myInvertedEdges.Contains (aEV))
5882           ++iNbEInverted;
5883 
5884         if (bAllEdgesInv)
5885           bAllEdgesInv = myInvalidEdges.Contains (aEV);
5886       }
5887 
5888       if (iNbEInverted > 1 || bAllEdgesInv)
5889       {
5890         theMVRInv.Add (aV);
5891       }
5892     }
5893   }
5894 }
5895 
5896 //=======================================================================
5897 //function : FindFacesForIntersection
5898 //purpose  : Looking for the faces around each invalidity for intersection
5899 //=======================================================================
FindFacesForIntersection(const TopoDS_Shape & theFInv,const TopTools_IndexedMapOfShape & theME,const TopTools_DataMapOfShapeListOfShape & theDMSF,const TopTools_MapOfShape & theMVInvAll,const Standard_Boolean theArtCase,TopTools_IndexedMapOfShape & theMFAvoid,TopTools_IndexedMapOfShape & theMFInt,TopTools_IndexedMapOfShape & theMFIntExt,TopTools_ListOfShape & theLFImInt)5900 void BRepOffset_BuildOffsetFaces::FindFacesForIntersection (const TopoDS_Shape& theFInv,
5901                                                             const TopTools_IndexedMapOfShape& theME,
5902                                                             const TopTools_DataMapOfShapeListOfShape& theDMSF,
5903                                                             const TopTools_MapOfShape& theMVInvAll,
5904                                                             const Standard_Boolean theArtCase,
5905                                                             TopTools_IndexedMapOfShape& theMFAvoid,
5906                                                             TopTools_IndexedMapOfShape& theMFInt,
5907                                                             TopTools_IndexedMapOfShape& theMFIntExt,
5908                                                             TopTools_ListOfShape& theLFImInt)
5909 {
5910   Standard_Integer i, aNbE = theME.Extent();
5911   //
5912   TopTools_IndexedMapOfShape aMShapes;
5913   //
5914   for (i = 1; i <= aNbE; ++i)
5915   {
5916     const TopoDS_Shape& aS = theME (i);
5917     if (!theDMSF.IsBound (aS))
5918     {
5919       continue;
5920     }
5921     //
5922     // in artificial case we intersect the faces which are close to invalidity
5923     Standard_Boolean bAvoid = theArtCase ?
5924       ((aS.ShapeType() == TopAbs_VERTEX) && !theMVInvAll.Contains (aS)) : Standard_False;
5925     //
5926     const TopTools_ListOfShape& aLF = theDMSF.Find (aS);
5927     TopTools_ListIteratorOfListOfShape aItLF (aLF);
5928     for (; aItLF.More(); aItLF.Next())
5929     {
5930       const TopoDS_Shape& aF = aItLF.Value();
5931       if (theMFInt.Contains (aF))
5932       {
5933         continue;
5934       }
5935       //
5936       if (bAvoid && myArtInvalidFaces.IsBound (aF))
5937       {
5938         theMFAvoid.Add (aF);
5939       }
5940       //
5941       theMFInt.Add (aF);
5942       //
5943       Standard_Boolean bUse = !aF.IsSame (theFInv);
5944       //
5945       const TopTools_ListOfShape& aLFIm = myOFImages.FindFromKey (aF);
5946       TopTools_ListIteratorOfListOfShape aItLFIm (aLFIm);
5947       for (; aItLFIm.More(); aItLFIm.Next())
5948       {
5949         const TopoDS_Shape& aFIm = aItLFIm.Value();
5950         theLFImInt.Append (aFIm);
5951         if (bUse)
5952         {
5953           TopExp::MapShapes (aFIm, TopAbs_EDGE, aMShapes);
5954         }
5955       }
5956     }
5957   }
5958   //
5959   if (theArtCase)
5960   {
5961     return;
5962   }
5963   //
5964   const TopTools_ListOfShape* pLFInv = mySSInterfs.Seek (theFInv);
5965   if (!pLFInv)
5966   {
5967     return;
5968   }
5969   //
5970   TopTools_MapOfShape aMF;
5971   TopTools_ListIteratorOfListOfShape aItLF (*pLFInv);
5972   for (; aItLF.More(); aItLF.Next())
5973   {
5974     const TopoDS_Shape& aF = aItLF.Value();
5975     aMF.Add (aF);
5976   }
5977   //
5978   // the faces should be unique in each place
5979   TopoDS_Compound aCF;
5980   BRep_Builder().MakeCompound (aCF);
5981   //
5982   TopTools_IndexedMapOfShape aMFToAdd;
5983   TopTools_DataMapOfShapeShape aDMFOr;
5984   //
5985   for (i = 1; i <= aNbE; ++i)
5986   {
5987     const TopoDS_Shape& aS = theME (i);
5988     const TopTools_ListOfShape* pLF = mySSInterfs.Seek (aS);
5989     if (!pLF)
5990     {
5991       continue;
5992     }
5993     //
5994     aItLF.Initialize (*pLF);
5995     for (; aItLF.More(); aItLF.Next())
5996     {
5997       const TopoDS_Shape& aF = aItLF.Value();
5998       if (theMFInt.Contains (aF) || aMFToAdd.Contains (aF) || !aMF.Contains (aF))
5999       {
6000         continue;
6001       }
6002       //
6003       // check if the face has some connection to already added for intersection faces
6004       const TopTools_ListOfShape& aLFIm = myOFImages.FindFromKey (aF);
6005       TopTools_ListIteratorOfListOfShape aItLFIm (aLFIm);
6006       for (; aItLFIm.More(); aItLFIm.Next())
6007       {
6008         const TopoDS_Shape& aFIm = aItLFIm.Value();
6009         TopExp_Explorer aExp (aFIm, TopAbs_EDGE);
6010         for (; aExp.More(); aExp.Next())
6011         {
6012           if (aMShapes.Contains (aExp.Current()))
6013           {
6014             break;
6015           }
6016         }
6017         if (aExp.More())
6018         {
6019           break;
6020         }
6021       }
6022       if (!aItLFIm.More())
6023       {
6024         continue;
6025       }
6026       //
6027       aMFToAdd.Add (aF);
6028       aItLFIm.Initialize (aLFIm);
6029       for (; aItLFIm.More(); aItLFIm.Next())
6030       {
6031         const TopoDS_Shape& aFIm = aItLFIm.Value();
6032         aDMFOr.Bind (aFIm, aF);
6033         BRep_Builder().Add (aCF, aFIm);
6034       }
6035     }
6036   }
6037   //
6038   if (aMFToAdd.IsEmpty())
6039   {
6040     return;
6041   }
6042   //
6043   TopTools_ListOfShape aLCB;
6044   BOPTools_AlgoTools::MakeConnexityBlocks (aCF, TopAbs_EDGE, TopAbs_FACE, aLCB);
6045   //
6046   if ((aLCB.Extent() == 1) && (aMFToAdd.Extent() > 1))
6047   {
6048     return;
6049   }
6050   //
6051   TopTools_ListIteratorOfListOfShape aItLCB (aLCB);
6052   for (; aItLCB.More(); aItLCB.Next())
6053   {
6054     const TopoDS_Shape& aCB = aItLCB.Value();
6055     aMFToAdd.Clear();
6056     TopExp_Explorer aExpF (aCB, TopAbs_FACE);
6057     for (; aExpF.More(); aExpF.Next())
6058     {
6059       const TopoDS_Shape& aFIm = aExpF.Current();
6060       aMFToAdd.Add (aDMFOr.Find (aFIm));
6061     }
6062     //
6063     if (aMFToAdd.Extent() == 1)
6064     {
6065       const TopoDS_Shape& aF = aMFToAdd (1);
6066       //
6067       theMFInt.Add (aF);
6068       theMFIntExt.Add (aF);
6069       //
6070       const TopTools_ListOfShape& aLFIm = myOFImages.FindFromKey (aF);
6071       TopTools_ListIteratorOfListOfShape aItLFIm (aLFIm);
6072       for (; aItLFIm.More(); aItLFIm.Next())
6073       {
6074         const TopoDS_Shape& aFIm = aItLFIm.Value();
6075         theLFImInt.Append (aFIm);
6076       }
6077     }
6078   }
6079 }
6080 
6081 //=======================================================================
6082 //function : ProcessCommonEdges
6083 //purpose  : Analyzing the common edges between splits of offset faces
6084 //=======================================================================
ProcessCommonEdges(const TopTools_ListOfShape & theLEC,const TopTools_IndexedMapOfShape & theME,const TopTools_DataMapOfShapeListOfShape & theMEInfETrim,const TopTools_MapOfShape & theAllInvs,const Standard_Boolean theForceUse,TopTools_IndexedMapOfShape & theMECV,TopTools_MapOfShape & theMECheckExt,TopTools_DataMapOfShapeListOfShape & theDMEETrim,TopTools_ListOfShape & theLFEi,TopTools_ListOfShape & theLFEj,TopTools_IndexedMapOfShape & theMEToInt)6085 void BRepOffset_BuildOffsetFaces::ProcessCommonEdges (const TopTools_ListOfShape& theLEC,
6086                                                       const TopTools_IndexedMapOfShape& theME,
6087                                                       const TopTools_DataMapOfShapeListOfShape& theMEInfETrim,
6088                                                       const TopTools_MapOfShape& theAllInvs,
6089                                                       const Standard_Boolean theForceUse,
6090                                                       TopTools_IndexedMapOfShape& theMECV,
6091                                                       TopTools_MapOfShape& theMECheckExt,
6092                                                       TopTools_DataMapOfShapeListOfShape& theDMEETrim,
6093                                                       TopTools_ListOfShape& theLFEi,
6094                                                       TopTools_ListOfShape& theLFEj,
6095                                                       TopTools_IndexedMapOfShape& theMEToInt)
6096 {
6097   TopTools_ListOfShape aLEC;
6098   // process common edges
6099   TopTools_ListIteratorOfListOfShape aItLE (theLEC);
6100   for (; aItLE.More(); aItLE.Next())
6101   {
6102     const TopoDS_Shape& aEC = aItLE.Value();
6103     //
6104     // check first if common edges are valid
6105     if (myInvalidEdges.Contains (aEC) && !myValidEdges.Contains (aEC))
6106     {
6107       continue;
6108     }
6109     //
6110     // common edge should have connection to current invalidity
6111     if (theME.Contains (aEC))
6112     {
6113       aLEC.Append (aEC);
6114       continue;
6115     }
6116     //
6117     TopoDS_Iterator aItV (aEC);
6118     for (; aItV.More(); aItV.Next())
6119     {
6120       const TopoDS_Shape& aVE = aItV.Value();
6121       if (theME.Contains (aVE))
6122       {
6123         aLEC.Append (aEC);
6124         break;
6125       }
6126     }
6127   }
6128   //
6129   Standard_Boolean bUseOnlyInf = aLEC.IsEmpty();
6130   if (bUseOnlyInf)
6131   {
6132     if (theForceUse)
6133     {
6134       aLEC = theLEC;
6135     }
6136     else
6137     {
6138       aItLE.Initialize (theLEC);
6139       for (; aItLE.More(); aItLE.Next())
6140       {
6141         const TopoDS_Shape& aEC = aItLE.Value();
6142         // check if all images of the origin of this edge
6143         // are not connected to any invalidity
6144         const TopoDS_Shape& aEInt = myETrimEInf->Find (aEC);
6145         const TopTools_ListOfShape& aLVE = theMEInfETrim.Find (aEInt);
6146         TopTools_ListIteratorOfListOfShape aItLVE (aLVE);
6147         for (; aItLVE.More(); aItLVE.Next())
6148         {
6149           const TopoDS_Shape& aECx = aItLVE.Value();
6150           if (theAllInvs.Contains (aECx) || myInvalidEdges.Contains (aECx))
6151           {
6152             return;
6153           }
6154           //
6155           TopoDS_Iterator aItV (aECx);
6156           for (; aItV.More(); aItV.Next())
6157           {
6158             if (theAllInvs.Contains (aItV.Value()))
6159             {
6160               return;
6161             }
6162           }
6163         }
6164         // use only one element
6165         if (aLEC.IsEmpty())
6166         {
6167           aLEC.Append (aEC);
6168         }
6169       }
6170     }
6171   }
6172   //
6173   aItLE.Initialize (aLEC);
6174   for (; aItLE.More(); aItLE.Next())
6175   {
6176     const TopoDS_Shape& aEC = aItLE.Value();
6177     //
6178     const TopoDS_Shape& aEInt = myETrimEInf->Find (aEC);
6179     if (!bUseOnlyInf)
6180     {
6181       // find the edges of the same original edge
6182       // and take their vertices as well
6183       const TopTools_ListOfShape& aLVE = theMEInfETrim.Find (aEInt);
6184       TopTools_ListIteratorOfListOfShape aItLVE (aLVE);
6185       for (; aItLVE.More(); aItLVE.Next())
6186       {
6187         const TopoDS_Shape& aECx = aItLVE.Value();
6188         //
6189         const TopTools_ListOfShape* pLEOr = myOEOrigins.Seek (aECx);
6190         if (!pLEOr || (pLEOr->Extent() == 1))
6191         {
6192           TopExp::MapShapes (aECx, TopAbs_VERTEX, theMECV);
6193         }
6194       }
6195       //
6196       // bind unlimited edge to its trimmed part in face to update maps of
6197       // images and origins in the future
6198       TopTools_ListOfShape* pLTAdded = theDMEETrim.ChangeSeek (aEInt);
6199       if (!pLTAdded)
6200       {
6201         pLTAdded = theDMEETrim.Bound (aEInt, TopTools_ListOfShape());
6202       }
6203       AppendToList (*pLTAdded, aEC);
6204     }
6205     else if (!theForceUse)
6206     {
6207       theMECheckExt.Add (aEInt);
6208     }
6209     //
6210     AppendToList (theLFEi, aEInt);
6211     AppendToList (theLFEj, aEInt);
6212     theMEToInt.Add (aEInt);
6213   }
6214 }
6215 
6216 namespace {
6217   //=======================================================================
6218   //function : FindOrigins
6219   //purpose  : Looking for the origin edges
6220   //=======================================================================
FindOrigins(const TopTools_ListOfShape & theLFIm1,const TopTools_ListOfShape & theLFIm2,const TopTools_IndexedMapOfShape & theME,const TopTools_DataMapOfShapeListOfShape & theOrigins,TopTools_ListOfShape & theLEOr)6221   static void FindOrigins (const TopTools_ListOfShape& theLFIm1,
6222                            const TopTools_ListOfShape& theLFIm2,
6223                            const TopTools_IndexedMapOfShape& theME,
6224                            const TopTools_DataMapOfShapeListOfShape& theOrigins,
6225                            TopTools_ListOfShape& theLEOr)
6226   {
6227     TopTools_MapOfShape aMFence;
6228     for (Standard_Integer i = 0; i < 2; ++i)
6229     {
6230       const TopTools_ListOfShape& aLF = !i ? theLFIm1 : theLFIm2;
6231       TopTools_ListOfShape::Iterator aIt (aLF);
6232       for (; aIt.More(); aIt.Next())
6233       {
6234         const TopoDS_Shape& aF = aIt.Value();
6235         //
6236         TopExp_Explorer aExp (aF, TopAbs_EDGE);
6237         for (; aExp.More(); aExp.Next())
6238         {
6239           const TopoDS_Shape& aE = aExp.Current();
6240           //
6241           if (theME.Contains (aE) && theOrigins.IsBound (aE))
6242           {
6243             const TopTools_ListOfShape& aLEOr = theOrigins.Find (aE);
6244             TopTools_ListOfShape::Iterator aItLE (aLEOr);
6245             for (; aItLE.More(); aItLE.Next())
6246             {
6247               const TopoDS_Shape& aEOr = aItLE.Value();
6248               //
6249               if (aMFence.Add (aEOr) && (aEOr.ShapeType() == TopAbs_EDGE))
6250               {
6251                 theLEOr.Append (aEOr);
6252               }
6253             }
6254           }
6255         }
6256       }
6257     }
6258   }
6259 }
6260 
6261 //=======================================================================
6262 //function : UpdateIntersectedFaces
6263 //purpose  : Updating the already interfered faces
6264 //=======================================================================
UpdateIntersectedFaces(const TopoDS_Shape & theFInv,const TopoDS_Shape & theFi,const TopoDS_Shape & theFj,const TopTools_ListOfShape & theLFInv,const TopTools_ListOfShape & theLFImi,const TopTools_ListOfShape & theLFImj,const TopTools_ListOfShape & theLFEi,const TopTools_ListOfShape & theLFEj,TopTools_IndexedMapOfShape & theMEToInt)6265 void BRepOffset_BuildOffsetFaces::UpdateIntersectedFaces (const TopoDS_Shape& theFInv,
6266                                                           const TopoDS_Shape& theFi,
6267                                                           const TopoDS_Shape& theFj,
6268                                                           const TopTools_ListOfShape& theLFInv,
6269                                                           const TopTools_ListOfShape& theLFImi,
6270                                                           const TopTools_ListOfShape& theLFImj,
6271                                                           const TopTools_ListOfShape& theLFEi,
6272                                                           const TopTools_ListOfShape& theLFEj,
6273                                                           TopTools_IndexedMapOfShape& theMEToInt)
6274 {
6275   // Find common edges in these two lists
6276   TopTools_MapOfShape aMEi;
6277   TopTools_ListIteratorOfListOfShape aItLE (theLFEi);
6278   for (; aItLE.More(); aItLE.Next())
6279   {
6280     const TopoDS_Shape& aE = aItLE.Value();
6281     aMEi.Add (aE);
6282   }
6283   //
6284   // find origins
6285   TopTools_IndexedMapOfShape aMEToFindOrigins;
6286   TopTools_ListOfShape aLEToFindOrigins;
6287   if (!theFi.IsSame (theFInv))
6288   {
6289     FindCommonParts (theLFImi, theLFInv, aLEToFindOrigins);
6290   }
6291   if (!theFj.IsSame (theFInv))
6292   {
6293     FindCommonParts (theLFImj, theLFInv, aLEToFindOrigins);
6294   }
6295   //
6296   TopTools_ListOfShape aLEOrInit;
6297   aItLE.Initialize (aLEToFindOrigins);
6298   for (; aItLE.More(); aItLE.Next())
6299   {
6300     const TopoDS_Shape& aEC = aItLE.Value();
6301     aMEToFindOrigins.Add (aEC);
6302   }
6303   //
6304   FindOrigins (theLFImi, theLFImj, aMEToFindOrigins, *myEdgesOrigins, aLEOrInit);
6305   //
6306   aItLE.Initialize (theLFEj);
6307   for (; aItLE.More(); aItLE.Next())
6308   {
6309     const TopoDS_Shape& aE = aItLE.Value();
6310     if (aMEi.Contains (aE))
6311     {
6312       theMEToInt.Add (aE);
6313       if (aLEOrInit.Extent())
6314       {
6315         if (myEdgesOrigins->IsBound (aE))
6316         {
6317           TopTools_ListOfShape& aLEOr = myEdgesOrigins->ChangeFind (aE);
6318           TopTools_ListIteratorOfListOfShape aItLEOr (aLEOrInit);
6319           for (; aItLEOr.More(); aItLEOr.Next())
6320           {
6321             const TopoDS_Shape& aEOr = aItLEOr.Value();
6322             AppendToList (aLEOr, aEOr);
6323           }
6324         }
6325         else
6326         {
6327           myEdgesOrigins->Bind (aE, aLEOrInit);
6328         }
6329       }
6330     }
6331   }
6332 }
6333 
6334 //=======================================================================
6335 //function : IntersectFaces
6336 //purpose  : Intersection of the pair of faces
6337 //=======================================================================
IntersectFaces(const TopoDS_Shape & theFInv,const TopoDS_Shape & theFi,const TopoDS_Shape & theFj,const TopTools_ListOfShape & theLFInv,const TopTools_ListOfShape & theLFImi,const TopTools_ListOfShape & theLFImj,TopTools_ListOfShape & theLFEi,TopTools_ListOfShape & theLFEj,TopTools_IndexedMapOfShape & theMECV,TopTools_IndexedMapOfShape & theMEToInt)6338 void BRepOffset_BuildOffsetFaces::IntersectFaces (const TopoDS_Shape& theFInv,
6339                                                   const TopoDS_Shape& theFi,
6340                                                   const TopoDS_Shape& theFj,
6341                                                   const TopTools_ListOfShape& theLFInv,
6342                                                   const TopTools_ListOfShape& theLFImi,
6343                                                   const TopTools_ListOfShape& theLFImj,
6344                                                   TopTools_ListOfShape& theLFEi,
6345                                                   TopTools_ListOfShape& theLFEj,
6346                                                   TopTools_IndexedMapOfShape& theMECV,
6347                                                   TopTools_IndexedMapOfShape& theMEToInt)
6348 {
6349   // intersect faces
6350   TopAbs_State aSide = TopAbs_OUT;
6351   TopTools_ListOfShape aLInt1, aLInt2;
6352   TopoDS_Edge aNullEdge;
6353   TopoDS_Face aNullFace;
6354   BRepOffset_Tool::Inter3D (TopoDS::Face (theFi), TopoDS::Face (theFj), aLInt1, aLInt2, aSide,
6355                             aNullEdge, aNullFace, aNullFace);
6356   //
6357   if (aLInt1.IsEmpty())
6358   {
6359     return;
6360   }
6361   //
6362   // find common vertices for trimming edges
6363   TopTools_ListOfShape aLCV;
6364   TopTools_ListIteratorOfListOfShape aItLE;
6365   FindCommonParts (theLFImi, theLFImj, aLCV, TopAbs_VERTEX);
6366   if (aLCV.Extent() > 1)
6367   {
6368     aItLE.Initialize (aLCV);
6369     for (; aItLE.More(); aItLE.Next())
6370     {
6371       const TopoDS_Shape& aCV = aItLE.Value();
6372       theMECV.Add (aCV);
6373     }
6374   }
6375   //
6376   // find origins
6377   TopTools_IndexedMapOfShape aMEToFindOrigins;
6378   TopTools_ListOfShape aLEToFindOrigins;
6379   if (!theFi.IsSame (theFInv))
6380   {
6381     FindCommonParts (theLFImi, theLFInv, aLEToFindOrigins);
6382   }
6383   if (!theFj.IsSame (theFInv))
6384   {
6385     FindCommonParts (theLFImj, theLFInv, aLEToFindOrigins);
6386   }
6387   TopTools_ListOfShape aLEOrInit;
6388   aItLE.Initialize (aLEToFindOrigins);
6389   for (; aItLE.More(); aItLE.Next())
6390   {
6391     const TopoDS_Shape& aEC = aItLE.Value();
6392     aMEToFindOrigins.Add (aEC);
6393   }
6394   //
6395   FindOrigins (theLFImi, theLFImj, aMEToFindOrigins, *myEdgesOrigins, aLEOrInit);
6396   //
6397   aItLE.Initialize (aLInt1);
6398   for (; aItLE.More(); aItLE.Next())
6399   {
6400     const TopoDS_Shape& aEInt = aItLE.Value();
6401     theLFEi.Append (aEInt);
6402     theLFEj.Append (aEInt);
6403     //
6404     if (aLEOrInit.Extent())
6405     {
6406       myEdgesOrigins->Bind (aEInt, aLEOrInit);
6407     }
6408     //
6409     theMEToInt.Add (aEInt);
6410   }
6411 }
6412 
6413 
6414 //=======================================================================
6415 //function : IntersectAndTrimEdges
6416 //purpose  : Intersection of the new intersection edges among themselves
6417 //=======================================================================
IntersectAndTrimEdges(const TopTools_IndexedMapOfShape & theMFInt,const TopTools_IndexedMapOfShape & theMEInt,const TopTools_DataMapOfShapeListOfShape & theDMEETrim,const TopTools_IndexedMapOfShape & theMSInv,const TopTools_IndexedMapOfShape & theMVE,const TopTools_MapOfShape & theVertsToAvoid,const TopTools_MapOfShape & theNewVertsToAvoid,const TopTools_MapOfShape & theMECheckExt,TopTools_MapOfShape & theMVBounds,TopTools_DataMapOfShapeListOfShape & theEImages)6418 void BRepOffset_BuildOffsetFaces::IntersectAndTrimEdges (const TopTools_IndexedMapOfShape& theMFInt,
6419                                                          const TopTools_IndexedMapOfShape& theMEInt,
6420                                                          const TopTools_DataMapOfShapeListOfShape& theDMEETrim,
6421                                                          const TopTools_IndexedMapOfShape& theMSInv,
6422                                                          const TopTools_IndexedMapOfShape& theMVE,
6423                                                          const TopTools_MapOfShape& theVertsToAvoid,
6424                                                          const TopTools_MapOfShape& theNewVertsToAvoid,
6425                                                          const TopTools_MapOfShape& theMECheckExt,
6426                                                          TopTools_MapOfShape& theMVBounds,
6427                                                          TopTools_DataMapOfShapeListOfShape& theEImages)
6428 {
6429   Standard_Integer i, aNb = theMEInt.Extent();
6430   if (!aNb)
6431   {
6432     return;
6433   }
6434   //
6435   TopTools_ListOfShape aLArgs;
6436   TopTools_MapOfShape aMFence;
6437   TopTools_ListIteratorOfListOfShape aIt, aIt1;
6438   TopExp_Explorer aExp;
6439   //
6440   // get vertices from the splits of intersected faces.
6441   // vertices are taken from the edges close to invalidity
6442   //
6443   TopTools_IndexedDataMapOfShapeListOfShape aDMVE;
6444   aNb = theMFInt.Extent();
6445   for (i = 1; i <= aNb; ++i)
6446   {
6447     const TopoDS_Shape& aF = theMFInt (i);
6448     const TopTools_ListOfShape& aLE = myFacesToRebuild.FindFromKey (aF);
6449     //
6450     aIt.Initialize (aLE);
6451     for (; aIt.More(); aIt.Next())
6452     {
6453       const TopoDS_Shape& aE = aIt.Value();
6454       TopExp::MapShapesAndAncestors (aE, TopAbs_VERTEX, TopAbs_EDGE, aDMVE);
6455       //
6456       aExp.Init (aE, TopAbs_VERTEX);
6457       for (; aExp.More(); aExp.Next())
6458       {
6459         const TopoDS_Shape& aV1 = aExp.Current();
6460         if (!theVertsToAvoid.Contains (aV1) && theMVE.Contains (aV1) && aMFence.Add (aV1))
6461         {
6462           aLArgs.Append (aV1);
6463         }
6464       }
6465     }
6466   }
6467   //
6468   aNb = theMSInv.Extent();
6469   for (i = 1; i <= aNb; ++i)
6470   {
6471     const TopoDS_Shape& aV = theMSInv (i);
6472     if (aV.ShapeType() != TopAbs_VERTEX)
6473     {
6474       continue;
6475     }
6476     //
6477     TopTools_ListOfShape* pLVE = aDMVE.ChangeSeek (aV);
6478     if (!pLVE)
6479     {
6480       continue;
6481     }
6482     //
6483     aIt.Initialize (*pLVE);
6484     for (; aIt.More(); aIt.Next())
6485     {
6486       const TopoDS_Shape& aE = aIt.Value();
6487       //
6488       aExp.Init (aE, TopAbs_VERTEX);
6489       for (; aExp.More(); aExp.Next())
6490       {
6491         const TopoDS_Shape& aV1 = aExp.Current();
6492         if (!theVertsToAvoid.Contains (aV1) && aMFence.Add (aV1))
6493         {
6494           aLArgs.Append (aV1);
6495         }
6496       }
6497     }
6498   }
6499   //
6500   // bounding vertices of untrimmed edges
6501   TopTools_ListOfShape aLVBounds;
6502   // new intersection edges
6503   TopTools_ListOfShape aLENew;
6504   // get edges to intersect
6505   TopTools_ListOfShape aLEInt;
6506   // Common intersection edges. Should be intersected separately
6507   TopTools_ListOfShape aLCE;
6508   //
6509   aNb = theMEInt.Extent();
6510   for (i = 1; i <= aNb; ++i)
6511   {
6512     const TopoDS_Shape& aE = theMEInt (i);
6513     if (theMECheckExt.Contains (aE))
6514     {
6515       // avoid trimming of the intersection edges by additional common edges
6516       aLCE.Append (aE);
6517       continue;
6518     }
6519     //
6520     if (!theDMEETrim.IsBound (aE))
6521     {
6522       aLENew.Append (aE);
6523     }
6524     //
6525     aLEInt.Append (aE);
6526     aLArgs.Append (aE);
6527     //
6528     aExp.Init (aE, TopAbs_VERTEX);
6529     for (; aExp.More(); aExp.Next())
6530     {
6531       const TopoDS_Shape& aV = aExp.Current();
6532       aLVBounds.Append (aV);
6533     }
6534   }
6535   //
6536   // Intersect Edges
6537   BOPAlgo_Builder aGF;
6538   aGF.SetArguments (aLArgs);
6539   aGF.Perform();
6540   if (aGF.HasErrors())
6541   {
6542     return;
6543   }
6544   //
6545   // update vertices to avoid with SD vertices
6546   aIt.Initialize (aLVBounds);
6547   for (; aIt.More(); aIt.Next())
6548   {
6549     const TopoDS_Shape& aV = aIt.Value();
6550     const TopTools_ListOfShape& aLVIm = aGF.Modified (aV);
6551     if (aLVIm.IsEmpty())
6552     {
6553       theMVBounds.Add (aV);
6554     }
6555     else
6556     {
6557       const TopoDS_Shape& aVIm = aLVIm.First();
6558       theMVBounds.Add (aVIm);
6559     }
6560   }
6561   //
6562   // find invalid splits of edges
6563   TopTools_MapOfShape aMEInv;
6564   GetInvalidEdges (theNewVertsToAvoid, theMVBounds, aGF, aMEInv);
6565   //
6566   BRep_Builder aBB;
6567   // get valid splits to intersect with the commons
6568   TopoDS_Compound aCEIm;
6569   aBB.MakeCompound (aCEIm);
6570   //
6571   // remove the splits containing vertices from invalid edges
6572   aIt.Initialize (aLEInt);
6573   for (; aIt.More(); aIt.Next())
6574   {
6575     const TopoDS_Shape& aE = aIt.Value();
6576     //
6577     TopTools_ListOfShape aLEIm = aGF.Modified (aE);
6578     if (aLEIm.IsEmpty())
6579     {
6580       continue;
6581     }
6582     //
6583     aIt1.Initialize (aLEIm);
6584     for (; aIt1.More(); )
6585     {
6586       const TopoDS_Shape& aEIm = aIt1.Value();
6587       //
6588       if (aMEInv.Contains (aEIm))
6589       {
6590         aLEIm.Remove (aIt1);
6591       }
6592       else
6593       {
6594         aBB.Add (aCEIm, aEIm);
6595         aIt1.Next();
6596       }
6597     }
6598     //
6599     if (aLEIm.Extent())
6600     {
6601       TopTools_ListOfShape* pLEIm = theEImages.ChangeSeek (aE);
6602       if (!pLEIm)
6603       {
6604         pLEIm = theEImages.Bound (aE, TopTools_ListOfShape());
6605       }
6606       pLEIm->Append (aLEIm);
6607     }
6608   }
6609   //
6610   if (!aLCE.Extent())
6611   {
6612     return;
6613   }
6614   //
6615   // trim common edges by other intersection edges
6616   BOPAlgo_Builder aGFCE;
6617   aGFCE.SetArguments (aLCE);
6618   aGFCE.AddArgument (aCEIm);
6619   aGFCE.Perform();
6620   //
6621   if (aGFCE.HasErrors())
6622   {
6623     return;
6624   }
6625   //
6626   const BOPDS_PDS& pDS = aGFCE.PDS();
6627   TopTools_ListIteratorOfListOfShape aItLCE (aLCE);
6628   for (; aItLCE.More(); aItLCE.Next())
6629   {
6630     const TopoDS_Shape& aE = aItLCE.Value();
6631     TopTools_ListOfShape aLEIm = aGFCE.Modified (aE);
6632     if (aLEIm.IsEmpty())
6633     {
6634       continue;
6635     }
6636     //
6637     // check if it's not coincide with some intersection edge
6638     BOPDS_ListIteratorOfListOfPaveBlock aItLPB (pDS->PaveBlocks (pDS->Index (aE)));
6639     for (; aItLPB.More(); aItLPB.Next())
6640     {
6641       if (pDS->IsCommonBlock (aItLPB.Value()))
6642       {
6643         // find with what it is a common
6644         const BOPDS_ListOfPaveBlock& aLPBC = pDS->CommonBlock (aItLPB.Value())->PaveBlocks();
6645         BOPDS_ListIteratorOfListOfPaveBlock aItLPBC (aLPBC);
6646         for (; aItLPBC.More(); aItLPBC.Next())
6647         {
6648           const TopoDS_Shape& aEC = pDS->Shape (aItLPBC.Value()->OriginalEdge());
6649           if (!theMECheckExt.Contains (aEC))
6650           {
6651             break;
6652           }
6653         }
6654         if (aItLPBC.More())
6655         {
6656           break;
6657         }
6658       }
6659     }
6660     if (aItLPB.More())
6661     {
6662       // avoid creation of unnecessary splits from commons which
6663       // coincide with intersection edges
6664       continue;
6665     }
6666     //
6667     // save the images
6668     TopTools_ListOfShape* pLEIm = theEImages.ChangeSeek (aE);
6669     if (!pLEIm)
6670     {
6671       pLEIm = theEImages.Bound (aE, TopTools_ListOfShape());
6672     }
6673     pLEIm->Append (aLEIm);
6674     //
6675     // save bounding vertices
6676     for (TopoDS_Iterator aItV (aE); aItV.More(); aItV.Next())
6677     {
6678       const TopoDS_Shape& aV = aItV.Value();
6679       const TopTools_ListOfShape& aLVIm = aGFCE.Modified (aV);
6680       theMVBounds.Add (aLVIm.IsEmpty() ? aV : aLVIm.First());
6681     }
6682   }
6683 }
6684 
6685 //=======================================================================
6686 //function : GetInvalidEdges
6687 //purpose  : Looking for the invalid edges by intersecting with invalid vertices
6688 //=======================================================================
GetInvalidEdges(const TopTools_MapOfShape & theVertsToAvoid,const TopTools_MapOfShape & theMVBounds,BOPAlgo_Builder & theGF,TopTools_MapOfShape & theMEInv)6689 void BRepOffset_BuildOffsetFaces::GetInvalidEdges (const TopTools_MapOfShape& theVertsToAvoid,
6690                                                    const TopTools_MapOfShape& theMVBounds,
6691                                                    BOPAlgo_Builder& theGF,
6692                                                    TopTools_MapOfShape& theMEInv)
6693 {
6694   if (theVertsToAvoid.IsEmpty())
6695   {
6696     return;
6697   }
6698   //
6699   TopTools_ListIteratorOfListOfShape aIt, aIt1;
6700   // get vertices created with intersection edges
6701   const TopoDS_Shape& aRes = theGF.Shape();
6702   TopTools_IndexedDataMapOfShapeListOfShape aDMVE;
6703   TopExp::MapShapesAndAncestors (aRes, TopAbs_VERTEX, TopAbs_EDGE, aDMVE);
6704   //
6705   const BOPDS_PDS& pDS = theGF.PDS();
6706   //
6707   // find invalid splits of edges
6708   // check if the vertex is invalid:
6709   // a. it may be the vertex SD with the vertices to avoid
6710   // b. or it may be the vertex which is created by the intersection
6711   //    of only existing edges, i.e. no new intersection edges goes
6712   //    through this vertex
6713   //
6714   TopTools_MapOfShape aMVInv;
6715   Standard_Integer i, aNb = aDMVE.Extent();
6716   for (i = 1; i <= aNb; ++i)
6717   {
6718     const TopoDS_Vertex& aV = TopoDS::Vertex (aDMVE.FindKey (i));
6719     if (theMVBounds.Contains (aV))
6720     {
6721       continue;
6722     }
6723     //
6724     Standard_Integer nV = pDS->Index (aV);
6725     if ((nV >= 0) && !pDS->IsNewShape (nV))
6726     {
6727       continue;
6728     }
6729     //
6730     TopTools_MapIteratorOfMapOfShape aItM (theVertsToAvoid);
6731     for (; aItM.More(); aItM.Next())
6732     {
6733       const TopoDS_Vertex& aVInv = *(TopoDS_Vertex*)&aItM.Value();
6734       Standard_Integer iFlag = BOPTools_AlgoTools::ComputeVV (aV, aVInv);
6735       if (!iFlag)
6736       {
6737         aMVInv.Add (aV);
6738         break;
6739       }
6740     }
6741     //
6742     if (aItM.More())
6743     {
6744       const TopTools_ListOfShape& aLVE = aDMVE.FindFromKey (aV);
6745       aIt.Initialize (aLVE);
6746       for (; aIt.More(); aIt.Next())
6747       {
6748         const TopoDS_Shape& aE = aIt.Value();
6749         theMEInv.Add (aE);
6750       }
6751     }
6752   }
6753 }
6754 
6755 //=======================================================================
6756 //function : UpdateValidEdges
6757 //purpose  : Making the new splits and updating the maps
6758 //=======================================================================
UpdateValidEdges(const TopTools_IndexedDataMapOfShapeListOfShape & theFLE,const TopTools_IndexedDataMapOfShapeListOfShape & theOENEdges,const TopTools_MapOfShape & theMVBounds,const TopTools_MapOfShape & theMEInvOnArt,TopTools_MapOfShape & theMECheckExt,TopTools_MapOfShape & theVertsToAvoid,TopTools_DataMapOfShapeListOfShape & theEImages,TopTools_DataMapOfShapeListOfShape & theEETrim,const Message_ProgressRange & theRange)6759 void BRepOffset_BuildOffsetFaces::UpdateValidEdges (const TopTools_IndexedDataMapOfShapeListOfShape& theFLE,
6760                                                     const TopTools_IndexedDataMapOfShapeListOfShape& theOENEdges,
6761                                                     const TopTools_MapOfShape& theMVBounds,
6762                                                     const TopTools_MapOfShape& theMEInvOnArt,
6763                                                     TopTools_MapOfShape& theMECheckExt,
6764                                                     TopTools_MapOfShape& theVertsToAvoid,
6765                                                     TopTools_DataMapOfShapeListOfShape& theEImages,
6766                                                     TopTools_DataMapOfShapeListOfShape& theEETrim,
6767                                                     const Message_ProgressRange& theRange)
6768 {
6769   Message_ProgressScope aPSOuter (theRange, "Updating edges", 10);
6770   // update images and origins of edges, plus update AsDes
6771   //
6772   // new edges
6773   TopTools_ListOfShape aLE;
6774   // back connection from edges to faces
6775   TopTools_DataMapOfShapeListOfShape aMELF;
6776   //
6777   TopTools_MapOfShape aMETmp;
6778   Standard_Integer i, aNb = theFLE.Extent();
6779   for (i = 1; i <= aNb; ++i)
6780   {
6781     const TopoDS_Face& aF = TopoDS::Face (theFLE.FindKey (i));
6782     //
6783     const TopTools_ListOfShape& aLEInt = theFLE (i);
6784     TopTools_ListIteratorOfListOfShape aItLE (aLEInt);
6785     for (; aItLE.More(); aItLE.Next())
6786     {
6787       const TopoDS_Shape& aE = aItLE.Value();
6788       if ((theMECheckExt.Contains (aE) || aMETmp.Contains (aE)) && !theEImages.IsBound (aE))
6789       {
6790         theMECheckExt.Remove (aE);
6791         aMETmp.Add (aE);
6792         continue;
6793       }
6794       TopTools_ListOfShape* pLF = aMELF.ChangeSeek (aE);
6795       if (!pLF)
6796       {
6797         pLF = aMELF.Bound (aE, TopTools_ListOfShape());
6798         aLE.Append (aE);
6799       }
6800       pLF->Append (aF);
6801     }
6802   }
6803   //
6804   if (aLE.IsEmpty())
6805   {
6806     return;
6807   }
6808   //
6809   // bounding edges, that are going to be replaced
6810   TopTools_MapOfShape aMEB;
6811   //
6812   // new intersection edges
6813   TopTools_MapOfShape aMENew;
6814   // map of old vertices
6815   TopTools_MapOfShape aMVOld;
6816   // back connection to untrimmed edges
6817   TopTools_DataMapOfShapeListOfShape aDMEOr;
6818   //
6819   // trim the new intersection edges
6820   TrimNewIntersectionEdges (aLE, theEETrim, theMVBounds, theMECheckExt,
6821                             theEImages, aMEB, aMVOld, aMENew, aDMEOr, aMELF);
6822   //
6823   if (theEImages.IsEmpty())
6824   {
6825     // No new splits is preserved
6826     // update intersection edges and exit
6827     UpdateNewIntersectionEdges (aLE, aMELF, theEImages, theEETrim);
6828     return;
6829   }
6830 
6831   aPSOuter.Next();
6832   if (!aPSOuter.More())
6833   {
6834     return;
6835   }
6836 
6837   BRep_Builder aBB;
6838 
6839   // Make connexity blocks of the invalid edges
6840   // and treat each block separately
6841 
6842   // Compound of all invalid edges to make the blocks
6843   TopoDS_Compound aCEAll;
6844   aBB.MakeCompound (aCEAll);
6845 
6846   Standard_Integer aNbE = theOENEdges.Extent();
6847   for (i = 1; i <= aNbE; ++i)
6848     aBB.Add (aCEAll, theOENEdges.FindKey (i));
6849 
6850   // Separate the edges into blocks
6851   TopTools_ListOfShape aLBlocks;
6852   BOPTools_AlgoTools::MakeConnexityBlocks (aCEAll, TopAbs_VERTEX, TopAbs_EDGE, aLBlocks);
6853 
6854   // Perform intersection of the new splits for each block
6855 
6856   // Intersected splits
6857   TopTools_IndexedDataMapOfShapeListOfShape aMBlocksSp;
6858 
6859   Message_ProgressScope aPSB (aPSOuter.Next(), NULL, aLBlocks.Extent());
6860   TopTools_ListIteratorOfListOfShape aItLB (aLBlocks);
6861   for (; aItLB.More(); aItLB.Next(), aPSB.Next())
6862   {
6863     if (!aPSB.More())
6864     {
6865       return;
6866     }
6867     const TopoDS_Shape& aBlock = aItLB.Value();
6868 
6869     // Get the list of new edges for the block
6870     TopTools_ListOfShape aBlockLENew;
6871     {
6872       // Fence map
6873       TopTools_MapOfShape aMEFence;
6874       TopExp_Explorer anExpE (aBlock, TopAbs_EDGE);
6875       for (; anExpE.More(); anExpE.Next())
6876       {
6877         const TopoDS_Shape& aE = anExpE.Current();
6878         const TopTools_ListOfShape& aLEInt = theOENEdges.FindFromKey (aE);
6879         TopTools_ListIteratorOfListOfShape aItLEInt (aLEInt);
6880         for (; aItLEInt.More(); aItLEInt.Next())
6881         {
6882           if (aMEFence.Add (aItLEInt.Value()))
6883             aBlockLENew.Append (aItLEInt.Value());
6884         }
6885       }
6886     }
6887 
6888     if (aBlockLENew.IsEmpty())
6889       continue;
6890 
6891     // Get the splits of new edges to intersect
6892     TopTools_ListOfShape aLSplits;
6893 
6894     TopTools_ListIteratorOfListOfShape aItLE (aBlockLENew);
6895     for (; aItLE.More(); aItLE.Next())
6896     {
6897       const TopoDS_Shape& aE = aItLE.Value();
6898       TopTools_ListOfShape* pLEIm = theEImages.ChangeSeek (aE);
6899       if (!pLEIm || pLEIm->IsEmpty())
6900         continue;
6901 
6902       TopTools_ListIteratorOfListOfShape aItLEIm (*pLEIm);
6903       for (; aItLEIm.More(); aItLEIm.Next())
6904         aLSplits.Append (aItLEIm.Value());
6905     }
6906 
6907     if (aLSplits.IsEmpty())
6908       continue;
6909 
6910     TopoDS_Shape aCE;
6911     if (aLSplits.Extent() > 1)
6912       // Intersect the new splits among themselves to avoid self-intersections
6913       IntersectEdges (aLSplits, aBlockLENew, theMVBounds, theVertsToAvoid,
6914                       aMENew, theMECheckExt, theEImages, aDMEOr, aMELF, aCE);
6915     else
6916       aCE = aLSplits.First();
6917 
6918     aMBlocksSp.Add (aCE, aBlockLENew);
6919   }
6920 
6921   // Perform filtering of the edges in two steps:
6922   // - Check each block separately using localized bounds
6923   //   taken only from the splits of faces of the current block;
6924   // - Intersect all splits together and filter the splits by all bounds.
6925 
6926   // FIRST STAGE - separate treatment of the blocks
6927 
6928   // Valid splits to be preserved on the first stage
6929   TopTools_MapOfShape aMEVal;
6930 
6931   // Blocks of valid edges on the first stage
6932   TopTools_ListOfShape aLValBlocks;
6933 
6934   Standard_Integer aNbB = aMBlocksSp.Extent();
6935   Message_ProgressScope aPSBSp (aPSOuter.Next(), NULL, aNbB);
6936   for (i = 1; i <= aNbB; ++i, aPSBSp.Next())
6937   {
6938     if (!aPSBSp.More())
6939     {
6940       return;
6941     }
6942     const TopoDS_Shape& aCE = aMBlocksSp.FindKey (i);
6943     const TopTools_ListOfShape& aBlockLENew = aMBlocksSp (i);
6944 
6945     // Get all participating faces to get the bounds
6946     TopTools_ListOfShape aLFaces;
6947     TopTools_ListIteratorOfListOfShape aItLE (aBlockLENew);
6948     for (; aItLE.More(); aItLE.Next())
6949     {
6950       const TopTools_ListOfShape* pLF = aMELF.Seek (aItLE.Value());
6951       if (!pLF)
6952         continue;
6953       TopTools_ListIteratorOfListOfShape aItLF (*pLF);
6954       for (; aItLF.More(); aItLF.Next())
6955         AppendToList (aLFaces, aItLF.Value());
6956     }
6957 
6958     // Localized bounds of the splits of the offset faces
6959     // to filter the new splits of the current block
6960     TopoDS_Shape aFilterBounds;
6961     GetBounds (aLFaces, aMEB, aFilterBounds);
6962 
6963     // Filter the splits by bounds
6964     TopTools_MapOfShape aMEInvLoc;
6965     GetInvalidEdgesByBounds (aCE, aFilterBounds, aMVOld, aMENew, aDMEOr, aMELF, theEImages,
6966                              theMECheckExt, theMEInvOnArt, theVertsToAvoid, aMEInvLoc);
6967 
6968     // Keep only valid edges of the block
6969     TopoDS_Compound aCEVal;
6970     aBB.MakeCompound (aCEVal);
6971 
6972     Standard_Boolean bKept = Standard_False;
6973 
6974     TopExp_Explorer anExpE (aCE, TopAbs_EDGE);
6975     for (; anExpE.More(); anExpE.Next())
6976     {
6977       const TopoDS_Shape& aESp = anExpE.Current();
6978       if (!aMEInvLoc.Contains (aESp) && aMEVal.Add (aESp))
6979       {
6980         aBB.Add (aCEVal, aESp);
6981         bKept = Standard_True;
6982       }
6983     }
6984 
6985     if (bKept)
6986       aLValBlocks.Append (aCEVal);
6987   }
6988 
6989   // Filter the images of edges after the first filtering stage
6990   TopoDS_Shape aSplits1;
6991   FilterSplits (aLE, aMEVal, Standard_False, theEImages, aSplits1);
6992 
6993   if (aLValBlocks.IsEmpty())
6994   {
6995     // update intersection edges
6996     UpdateNewIntersectionEdges (aLE, aMELF, theEImages, theEETrim);
6997     return;
6998   }
6999 
7000   aPSOuter.Next();
7001   if (!aPSOuter.More())
7002   {
7003     return;
7004   }
7005 
7006   // SECOND STAGE - Filter the remaining splits together
7007 
7008   // Add for intersection already removed new edges using them
7009   // as markers for other invalid edges
7010   aNbB = aMBlocksSp.Extent();
7011   for (i = 1; i <= aNbB; ++i)
7012   {
7013     const TopoDS_Shape& aCE = aMBlocksSp.FindKey (i);
7014     for (TopExp_Explorer anExp (aCE, TopAbs_EDGE); anExp.More(); anExp.Next())
7015     {
7016       const TopoDS_Shape& aEIm = anExp.Current();
7017       if (aMENew.Contains (aEIm) && !aMEVal.Contains (aEIm))
7018         aLValBlocks.Append (aEIm);
7019     }
7020   }
7021 
7022   if (aLValBlocks.Extent() > 1)
7023     // intersect the new splits among themselves to avoid self-intersections
7024     IntersectEdges (aLValBlocks, aLE, theMVBounds, theVertsToAvoid, aMENew,
7025                     theMECheckExt, theEImages, aDMEOr, aMELF, aSplits1);
7026   else
7027     aSplits1 = aLValBlocks.First();
7028 
7029   aPSOuter.Next();
7030   if (!aPSOuter.More())
7031   {
7032     return;
7033   }
7034 
7035   // Get all faces to get the bounds from their splits
7036   TopTools_ListOfShape aLFaces;
7037   for (i = 1; i <= myOFImages.Extent(); ++i)
7038     aLFaces.Append (myOFImages.FindKey (i));
7039 
7040   // Bounds of the splits of the offset faces to filter the new splits
7041   TopoDS_Shape aFilterBounds;
7042   GetBounds (aLFaces, aMEB, aFilterBounds);
7043 
7044   // Filter the splits by intersection with bounds
7045   TopTools_MapOfShape aMEInv;
7046   GetInvalidEdgesByBounds (aSplits1, aFilterBounds, aMVOld, aMENew, aDMEOr, aMELF,
7047                            theEImages, theMECheckExt, theMEInvOnArt, theVertsToAvoid, aMEInv);
7048 
7049   // Filter the images of edges after the second filtering stage
7050   // and combine all valid edges into a single compound
7051   TopoDS_Shape aSplits;
7052   FilterSplits (aLE, aMEInv, Standard_True, theEImages, aSplits);
7053 
7054   aPSOuter.Next();
7055   if (!aPSOuter.More())
7056   {
7057     return;
7058   }
7059 
7060   // get bounds to update
7061   // we need to update the edges of all the affected faces
7062   TopTools_ListOfShape aLF;
7063   // prepare the vertices from new splits of edges
7064   TopTools_IndexedMapOfShape aMVSp;
7065   TopExp::MapShapes (aSplits, TopAbs_VERTEX, aMVSp);
7066   //
7067   Standard_Integer aNbF = myOFImages.Extent();
7068   for (i = 1; i <= aNbF; ++i)
7069   {
7070     const TopoDS_Shape& aF = myOFImages.FindKey (i);
7071     if (theFLE.Contains (aF))
7072     {
7073       aLF.Append (aF);
7074       continue;
7075     }
7076     //
7077     // check the splits of faces to have vertices from splits
7078     const TopTools_ListOfShape& aLFIm = myOFImages (i);
7079     TopTools_ListIteratorOfListOfShape aItLFIm (aLFIm);
7080     for (; aItLFIm.More(); aItLFIm.Next())
7081     {
7082       const TopoDS_Shape& aFIm = aItLFIm.Value();
7083       //
7084       TopExp_Explorer aExpV (aFIm, TopAbs_VERTEX);
7085       for (; aExpV.More(); aExpV.Next())
7086       {
7087         const TopoDS_Shape& aV = aExpV.Current();
7088         if (aMVSp.Contains (aV))
7089         {
7090           break;
7091         }
7092       }
7093       //
7094       if (aExpV.More())
7095       {
7096         break;
7097       }
7098     }
7099     //
7100     if (aItLFIm.More())
7101     {
7102       aLF.Append (aF);
7103     }
7104   }
7105   //
7106   // get bounds from splits of faces of aLF
7107   TopoDS_Shape aBounds;
7108   TopTools_ListOfShape aLAValid, aLABounds;
7109   GetBoundsToUpdate (aLF, aMEB, aLABounds, aLAValid, aBounds);
7110   //
7111   // Intersect valid splits with bounds and update both
7112   BOPAlgo_Builder aGF;
7113   aGF.AddArgument (aBounds);
7114   aGF.AddArgument (aSplits);
7115   aGF.Perform (aPSOuter.Next (3));
7116   //
7117   // update splits
7118   UpdateImages (aLE, theEImages, aGF, myModifiedEdges);
7119   //
7120   // update new intersection edges
7121   UpdateNewIntersectionEdges (aLE, aMELF, theEImages, theEETrim);
7122   //
7123   // update bounds
7124   UpdateImages (aLAValid, myOEImages, aGF, myModifiedEdges);
7125   UpdateOrigins (aLABounds, myOEOrigins, aGF);
7126   UpdateOrigins (aLABounds, *myEdgesOrigins, aGF);
7127   UpdateIntersectedEdges (aLABounds, aGF);
7128   //
7129   // update the EdgesToAvoid with the splits
7130   TopTools_IndexedMapOfShape aNewEdges;
7131   const TopTools_ListOfShape* pSplitsIm = aGF.Images().Seek (aSplits);
7132   if (pSplitsIm)
7133   {
7134     TopTools_ListIteratorOfListOfShape aItSpIm (*pSplitsIm);
7135     for (; aItSpIm.More(); aItSpIm.Next())
7136     {
7137       TopExp::MapShapes (aItSpIm.Value(), TopAbs_EDGE, aNewEdges);
7138     }
7139   }
7140   //
7141   // Rebuild the map of edges to avoid, using the intersection results
7142   TopTools_IndexedMapOfShape aMEAvoid;
7143   // GF's data structure
7144   const BOPDS_PDS& pDS = aGF.PDS();
7145 
7146   aNbE = myEdgesToAvoid.Extent();
7147   for (i = 1; i <= aNbE; ++i)
7148   {
7149     const TopoDS_Shape& aE = myEdgesToAvoid (i);
7150     const TopTools_ListOfShape& aLEIm = aGF.Modified (aE);
7151 
7152     // Only untouched and fully coinciding edges should be kept in the avoid map
7153     Standard_Boolean bKeep = aLEIm.IsEmpty();
7154     if (aLEIm.Extent() == 1 && aE.IsSame (aLEIm.First()))
7155     {
7156       const BOPDS_ListOfPaveBlock& aLPB = pDS->PaveBlocks (pDS->Index (aE));
7157       if (aLPB.Extent() == 1)
7158       {
7159         const Handle(BOPDS_PaveBlock)& aPB = aLPB.First();
7160         const Handle(BOPDS_CommonBlock)& aCB = pDS->CommonBlock (aPB);
7161         if (!aCB.IsNull())
7162         {
7163           const BOPDS_ListOfPaveBlock& aLPBCB = aCB->PaveBlocks();
7164           BOPDS_ListIteratorOfListOfPaveBlock aItLPB (aLPBCB);
7165           for (; aItLPB.More(); aItLPB.Next())
7166           {
7167             if (pDS->PaveBlocks (aItLPB.Value()->OriginalEdge()).Extent() > 1)
7168               break;
7169           }
7170           bKeep = !aItLPB.More();
7171         }
7172       }
7173     }
7174 
7175     if (bKeep)
7176     {
7177       // keep the original edge
7178       aMEAvoid.Add (aE);
7179       continue;
7180     }
7181 
7182     TopTools_ListIteratorOfListOfShape aItLEIm (aLEIm);
7183     for (; aItLEIm.More(); aItLEIm.Next())
7184     {
7185       const TopoDS_Shape& aEIm = aItLEIm.Value();
7186       if (!aNewEdges.Contains (aEIm))
7187         aMEAvoid.Add (aEIm);
7188     }
7189   }
7190   myEdgesToAvoid = aMEAvoid;
7191 }
7192 
7193 //=======================================================================
7194 //function : TrimNewIntersectionEdges
7195 //purpose  :
7196 //=======================================================================
TrimNewIntersectionEdges(const TopTools_ListOfShape & theLE,const TopTools_DataMapOfShapeListOfShape & theEETrim,const TopTools_MapOfShape & theMVBounds,TopTools_MapOfShape & theMECheckExt,TopTools_DataMapOfShapeListOfShape & theEImages,TopTools_MapOfShape & theMEB,TopTools_MapOfShape & theMVOld,TopTools_MapOfShape & theMENew,TopTools_DataMapOfShapeListOfShape & theDMEOr,TopTools_DataMapOfShapeListOfShape & theMELF)7197 void BRepOffset_BuildOffsetFaces::TrimNewIntersectionEdges (const TopTools_ListOfShape& theLE,
7198                                                             const TopTools_DataMapOfShapeListOfShape& theEETrim,
7199                                                             const TopTools_MapOfShape& theMVBounds,
7200                                                             TopTools_MapOfShape& theMECheckExt,
7201                                                             TopTools_DataMapOfShapeListOfShape& theEImages,
7202                                                             TopTools_MapOfShape& theMEB,
7203                                                             TopTools_MapOfShape& theMVOld,
7204                                                             TopTools_MapOfShape& theMENew,
7205                                                             TopTools_DataMapOfShapeListOfShape& theDMEOr,
7206                                                             TopTools_DataMapOfShapeListOfShape& theMELF)
7207 {
7208   TopTools_ListIteratorOfListOfShape aIt, aIt1;
7209   aIt.Initialize (theLE);
7210   for (; aIt.More(); aIt.Next())
7211   {
7212     const TopoDS_Shape& aE = aIt.Value();
7213     //
7214     Standard_Boolean bCheckExt = theMECheckExt.Remove (aE);
7215     //
7216     Standard_Boolean bOld = theEETrim.IsBound (aE);
7217     if (bOld)
7218     {
7219       const TopTools_ListOfShape& aLET = theEETrim.Find (aE);
7220       aIt1.Initialize (aLET);
7221       for (; aIt1.More(); aIt1.Next())
7222       {
7223         const TopoDS_Shape& aET = aIt1.Value();
7224         theMEB.Add (aET);
7225         TopExp_Explorer aExpV (aET, TopAbs_VERTEX);
7226         for (; aExpV.More(); aExpV.Next())
7227         {
7228           const TopoDS_Shape& aV = aExpV.Current();
7229           theMVOld.Add (aV);
7230         }
7231       }
7232     }
7233     //
7234     if (!theEImages.IsBound (aE))
7235     {
7236       continue;
7237     }
7238     //
7239     TopTools_ListOfShape& aLEIm = theEImages.ChangeFind (aE);
7240     if (aLEIm.IsEmpty())
7241     {
7242       theEImages.UnBind (aE);
7243       continue;
7244     }
7245     //
7246     TopoDS_Shape aCEIm;
7247     TopTools_MapOfShape aMEVBounds;
7248     //
7249     if (aLEIm.Extent() > 1)
7250     {
7251       TopTools_IndexedMapOfShape aMV;
7252       // fuse these parts
7253       BOPAlgo_Builder aGFE;
7254       TopTools_ListIteratorOfListOfShape aItLEIm (aLEIm);
7255       for (; aItLEIm.More(); aItLEIm.Next())
7256       {
7257         const TopoDS_Shape& aEIm = aItLEIm.Value();
7258         aGFE.AddArgument (aEIm);
7259         TopExp::MapShapes (aEIm, TopAbs_VERTEX, aMV);
7260       }
7261       //
7262       // add two bounding vertices of this edge to the operation
7263       TopoDS_Vertex aV1, aV2;
7264       TopExp::Vertices (TopoDS::Edge (aE), aV1, aV2);
7265       //
7266       aGFE.AddArgument (aV1);
7267       aGFE.AddArgument (aV2);
7268       aMV.Add (aV1);
7269       aMV.Add (aV2);
7270       //
7271       aGFE.Perform();
7272       if (!aGFE.HasErrors())
7273       {
7274         // get images of bounding vertices to remove splits containing them
7275         // in case some of the bounding edges has been interfered
7276         // during operation it is necessary to update their images as well
7277         Standard_Integer iV, aNbV = aMV.Extent();
7278         for (iV = 1; iV <= aNbV; ++iV)
7279         {
7280           const TopoDS_Shape& aV = aMV (iV);
7281           if (theMVBounds.Contains (aV) || aV.IsSame (aV1) || aV.IsSame (aV2))
7282           {
7283             const TopTools_ListOfShape& aLVIm = aGFE.Modified (aV);
7284             aMEVBounds.Add (aLVIm.IsEmpty() ? aV : aLVIm.First());
7285           }
7286         }
7287         //
7288         aCEIm = aGFE.Shape();
7289       }
7290     }
7291     else
7292     {
7293       aCEIm = aLEIm.First();
7294     }
7295     //
7296     aLEIm.Clear();
7297     //
7298     TopExp_Explorer aExp (aCEIm, TopAbs_EDGE);
7299     for (; aExp.More(); aExp.Next())
7300     {
7301       const TopoDS_Shape& aEIm = aExp.Current();
7302       //
7303       // check the split not to contain bounding vertices
7304       TopoDS_Iterator aItV (aEIm);
7305       for (; aItV.More(); aItV.Next())
7306       {
7307         const TopoDS_Shape& aV = aItV.Value();
7308         if (aMEVBounds.Contains (aV) || theMVBounds.Contains (aV))
7309         {
7310           break;
7311         }
7312       }
7313       //
7314       if (!aItV.More())
7315       {
7316         aLEIm.Append (aEIm);
7317         //
7318         theDMEOr.Bound (aEIm, TopTools_ListOfShape())->Append (aE);
7319       }
7320     }
7321     //
7322     if (aLEIm.IsEmpty())
7323     {
7324       theEImages.UnBind (aE);
7325     }
7326     else
7327     {
7328       const TopTools_ListOfShape& aLFE = theMELF.Find (aE);
7329       TopTools_ListIteratorOfListOfShape aItLEIm (aLEIm);
7330       for (; aItLEIm.More(); aItLEIm.Next())
7331       {
7332         const TopoDS_Shape& aEIm = aItLEIm.Value();
7333         TopTools_ListOfShape* pLFEIm = theMELF.ChangeSeek (aEIm);
7334         if (!pLFEIm)
7335         {
7336           pLFEIm = theMELF.Bound (aEIm, TopTools_ListOfShape());
7337         }
7338         TopTools_ListIteratorOfListOfShape aItLF (aLFE);
7339         for (; aItLF.More(); aItLF.Next())
7340         {
7341           AppendToList (*pLFEIm, aItLF.Value());
7342         }
7343         //
7344         if (bCheckExt)
7345         {
7346           theMECheckExt.Add (aEIm);
7347         }
7348         else if (!bOld)
7349         {
7350           theMENew.Add (aEIm);
7351         }
7352       }
7353     }
7354   }
7355 }
7356 
7357 //=======================================================================
7358 //function : IntersectEdges
7359 //purpose  : Intersecting the trimmed edges to avoid self-intersections
7360 //=======================================================================
IntersectEdges(const TopTools_ListOfShape & theLA,const TopTools_ListOfShape & theLE,const TopTools_MapOfShape & theMVBounds,const TopTools_MapOfShape & theVertsToAvoid,TopTools_MapOfShape & theMENew,TopTools_MapOfShape & theMECheckExt,TopTools_DataMapOfShapeListOfShape & theEImages,TopTools_DataMapOfShapeListOfShape & theDMEOr,TopTools_DataMapOfShapeListOfShape & theMELF,TopoDS_Shape & theSplits)7361 void BRepOffset_BuildOffsetFaces::IntersectEdges (const TopTools_ListOfShape& theLA,
7362                                                   const TopTools_ListOfShape& theLE,
7363                                                   const TopTools_MapOfShape& theMVBounds,
7364                                                   const TopTools_MapOfShape& theVertsToAvoid,
7365                                                   TopTools_MapOfShape& theMENew,
7366                                                   TopTools_MapOfShape& theMECheckExt,
7367                                                   TopTools_DataMapOfShapeListOfShape& theEImages,
7368                                                   TopTools_DataMapOfShapeListOfShape& theDMEOr,
7369                                                   TopTools_DataMapOfShapeListOfShape& theMELF,
7370                                                   TopoDS_Shape& theSplits)
7371 {
7372   BOPAlgo_Builder aGFA;
7373   aGFA.SetArguments (theLA);
7374   aGFA.Perform();
7375   if (aGFA.HasErrors())
7376   {
7377     // just copy input to the result
7378     TopoDS_Compound aSp;
7379     BRep_Builder aBB;
7380     aBB.MakeCompound (aSp);
7381     TopTools_ListIteratorOfListOfShape anIt (theLA);
7382     for (; anIt.More(); anIt.Next())
7383     {
7384       const TopoDS_Shape& aE = anIt.Value();
7385       aBB.Add (aSp, aE);
7386     }
7387     theSplits = aSp;
7388     return;
7389   }
7390   //
7391   UpdateImages (theLE, theEImages, aGFA, myModifiedEdges);
7392   //
7393   // compound of valid splits
7394   theSplits = aGFA.Shape();
7395   //
7396   TopTools_ListIteratorOfListOfShape aIt, aIt1;
7397 
7398   // prepare list of edges to update
7399   TopTools_ListOfShape aLEInput;
7400   for (aIt.Initialize (theLA); aIt.More(); aIt.Next())
7401   {
7402     TopExp_Explorer anExpE (aIt.Value(), TopAbs_EDGE);
7403     for (; anExpE.More(); anExpE.Next())
7404       aLEInput.Append (anExpE.Current());
7405   }
7406 
7407   // update new edges
7408   aIt.Initialize (aLEInput);
7409   for (; aIt.More(); aIt.Next())
7410   {
7411     const TopoDS_Shape& aE = aIt.Value();
7412     if (!theMENew.Contains (aE))
7413       continue;
7414 
7415     const TopTools_ListOfShape& aLEIm = aGFA.Modified (aE);
7416     if (aLEIm.IsEmpty())
7417       continue;
7418 
7419     theMENew.Remove (aE);
7420     aIt1.Initialize (aLEIm);
7421     for (; aIt1.More(); aIt1.Next())
7422       theMENew.Add (aIt1.Value());
7423   }
7424   //
7425   // update edges after intersection for extended checking
7426   aIt.Initialize (aLEInput);
7427   for (; aIt.More(); aIt.Next())
7428   {
7429     const TopoDS_Shape& aE = aIt.Value();
7430     const TopTools_ListOfShape& aLEIm = aGFA.Modified (aE);
7431     if (aLEIm.IsEmpty())
7432     {
7433       continue;
7434     }
7435     //
7436     if (theMECheckExt.Contains (aE))
7437     {
7438       aIt1.Initialize (aLEIm);
7439       for (; aIt1.More(); aIt1.Next())
7440       {
7441         theMECheckExt.Add (aIt1.Value());
7442       }
7443       theMECheckExt.Remove (aE);
7444     }
7445     //
7446     const TopTools_ListOfShape& aLFE = theMELF.Find (aE);
7447     aIt1.Initialize (aLEIm);
7448     for (; aIt1.More(); aIt1.Next())
7449     {
7450       const TopoDS_Shape& aEIm = aIt1.Value();
7451       TopTools_ListOfShape* pLFEIm = theMELF.ChangeSeek (aEIm);
7452       if (!pLFEIm)
7453       {
7454         pLFEIm = theMELF.Bound (aEIm, TopTools_ListOfShape());
7455       }
7456       TopTools_ListIteratorOfListOfShape aItLF (aLFE);
7457       for (; aItLF.More(); aItLF.Next())
7458       {
7459         AppendToList (*pLFEIm, aItLF.Value());
7460       }
7461     }
7462   }
7463   //
7464   TopTools_MapOfShape aMEInv;
7465   GetInvalidEdges (theVertsToAvoid, theMVBounds, aGFA, aMEInv);
7466   if (aMEInv.Extent())
7467   {
7468     // update shape
7469     TopoDS_Compound aSp;
7470     BRep_Builder aBB;
7471     aBB.MakeCompound (aSp);
7472     TopExp_Explorer aExp (theSplits, TopAbs_EDGE);
7473     for (; aExp.More(); aExp.Next())
7474     {
7475       const TopoDS_Shape& aE = aExp.Current();
7476       if (!aMEInv.Contains (aE))
7477       {
7478         aBB.Add (aSp, aE);
7479       }
7480     }
7481     theSplits = aSp;
7482   }
7483   //
7484   // update origins
7485   UpdateOrigins (aLEInput, theDMEOr, aGFA);
7486 }
7487 
7488 //=======================================================================
7489 //function : GetBounds
7490 //purpose  : Getting edges from the splits of offset faces
7491 //=======================================================================
GetBounds(const TopTools_ListOfShape & theLFaces,const TopTools_MapOfShape & theMEB,TopoDS_Shape & theBounds)7492 void BRepOffset_BuildOffsetFaces::GetBounds (const TopTools_ListOfShape& theLFaces,
7493                                              const TopTools_MapOfShape& theMEB,
7494                                              TopoDS_Shape& theBounds)
7495 {
7496   BRep_Builder aBB;
7497   // Make compound of edges contained in the splits of faces
7498   TopoDS_Compound aBounds;
7499   aBB.MakeCompound (aBounds);
7500   // Fence map
7501   TopTools_MapOfShape aMFence;
7502 
7503   TopTools_ListIteratorOfListOfShape aItLF (theLFaces);
7504   for (; aItLF.More(); aItLF.Next())
7505   {
7506     const TopTools_ListOfShape* pLFIm = myOFImages.Seek (aItLF.Value());
7507     if (!pLFIm)
7508       continue;
7509     TopTools_ListIteratorOfListOfShape aIt (*pLFIm);
7510     for (; aIt.More(); aIt.Next())
7511     {
7512       const TopoDS_Shape& aFIm = aIt.Value();
7513       //
7514       TopExp_Explorer aExpE (aFIm, TopAbs_EDGE);
7515       for (; aExpE.More(); aExpE.Next())
7516       {
7517         const TopoDS_Shape& aEIm = aExpE.Current();
7518         if (!theMEB.Contains (aEIm) && aMFence.Add (aEIm))
7519         {
7520           aBB.Add (aBounds, aEIm);
7521         }
7522       }
7523     }
7524   }
7525   theBounds = aBounds;
7526 }
7527 
7528 //=======================================================================
7529 //function : GetBoundsToUpdate
7530 //purpose  : Get bounding edges that should be updated
7531 //=======================================================================
GetBoundsToUpdate(const TopTools_ListOfShape & theLF,const TopTools_MapOfShape & theMEB,TopTools_ListOfShape & theLABounds,TopTools_ListOfShape & theLAValid,TopoDS_Shape & theBounds)7532 void BRepOffset_BuildOffsetFaces::GetBoundsToUpdate (const TopTools_ListOfShape& theLF,
7533                                                      const TopTools_MapOfShape& theMEB,
7534                                                      TopTools_ListOfShape& theLABounds,
7535                                                      TopTools_ListOfShape& theLAValid,
7536                                                      TopoDS_Shape& theBounds)
7537 {
7538   // get all edges
7539   TopoDS_Compound aBounds;
7540   BRep_Builder aBB;
7541   aBB.MakeCompound (aBounds);
7542   //
7543   TopTools_MapOfShape aMAValid, aMFence;
7544   //
7545   TopTools_ListIteratorOfListOfShape aItLF (theLF);
7546   for (; aItLF.More(); aItLF.Next())
7547   {
7548     const TopoDS_Shape& aF = aItLF.Value();
7549     //
7550     TopTools_IndexedMapOfShape aMDE;
7551     const TopTools_ListOfShape& aLFDes = myAsDes->Descendant (aF);
7552     TopTools_ListIteratorOfListOfShape aItLFDes (aLFDes);
7553     for (; aItLFDes.More(); aItLFDes.Next())
7554     {
7555       const TopoDS_Shape& aED = aItLFDes.Value();
7556       const TopTools_ListOfShape* pLEDIm = myOEImages.Seek (aED);
7557       if (!pLEDIm)
7558       {
7559         aMDE.Add (aED);
7560         continue;
7561       }
7562       //
7563       TopTools_ListIteratorOfListOfShape aItLEDIm (*pLEDIm);
7564       for (; aItLEDIm.More(); aItLEDIm.Next())
7565       {
7566         const TopoDS_Shape& aEDIm = aItLEDIm.Value();
7567         aMDE.Add (aEDIm);
7568       }
7569     }
7570     //
7571     Standard_Integer j, aNbE = aMDE.Extent();
7572     for (j = 1; j <= aNbE; ++j)
7573     {
7574       const TopoDS_Edge& aEIm = TopoDS::Edge (aMDE (j));
7575       //
7576       if (!theMEB.Contains (aEIm) && aMFence.Add (aEIm))
7577       {
7578         aBB.Add (aBounds, aEIm);
7579         theLABounds.Append (aEIm);
7580       }
7581       //
7582       const TopTools_ListOfShape* pLO = myOEOrigins.Seek (aEIm);
7583       if (pLO)
7584       {
7585         TopTools_ListIteratorOfListOfShape aItLO (*pLO);
7586         for (; aItLO.More(); aItLO.Next())
7587         {
7588           const TopoDS_Shape& aEO = aItLO.Value();
7589           //
7590           if (aMAValid.Add (aEO))
7591           {
7592             theLAValid.Append (aEO);
7593           }
7594         }
7595       }
7596       else
7597       {
7598         if (aMAValid.Add (aEIm))
7599         {
7600           theLAValid.Append (aEIm);
7601         }
7602       }
7603     }
7604   }
7605   theBounds = aBounds;
7606 }
7607 
7608 //=======================================================================
7609 //function : GetInvalidEdgesByBounds
7610 //purpose  : Filter new splits by intersection with bounds
7611 //=======================================================================
GetInvalidEdgesByBounds(const TopoDS_Shape & theSplits,const TopoDS_Shape & theBounds,const TopTools_MapOfShape & theMVOld,const TopTools_MapOfShape & theMENew,const TopTools_DataMapOfShapeListOfShape & theDMEOr,const TopTools_DataMapOfShapeListOfShape & theMELF,const TopTools_DataMapOfShapeListOfShape & theEImages,const TopTools_MapOfShape & theMECheckExt,const TopTools_MapOfShape & theMEInvOnArt,TopTools_MapOfShape & theVertsToAvoid,TopTools_MapOfShape & theMEInv)7612 void BRepOffset_BuildOffsetFaces::GetInvalidEdgesByBounds (const TopoDS_Shape& theSplits,
7613                                                            const TopoDS_Shape& theBounds,
7614                                                            const TopTools_MapOfShape& theMVOld,
7615                                                            const TopTools_MapOfShape& theMENew,
7616                                                            const TopTools_DataMapOfShapeListOfShape& theDMEOr,
7617                                                            const TopTools_DataMapOfShapeListOfShape& theMELF,
7618                                                            const TopTools_DataMapOfShapeListOfShape& theEImages,
7619                                                            const TopTools_MapOfShape& theMECheckExt,
7620                                                            const TopTools_MapOfShape& theMEInvOnArt,
7621                                                            TopTools_MapOfShape& theVertsToAvoid,
7622                                                            TopTools_MapOfShape& theMEInv)
7623 {
7624   // map splits to check the vertices of edges
7625   TopTools_IndexedDataMapOfShapeListOfShape aDMVE;
7626   TopExp::MapShapesAndAncestors (theSplits, TopAbs_VERTEX, TopAbs_EDGE, aDMVE);
7627   //
7628   BOPAlgo_Section aSec;
7629   aSec.AddArgument (theSplits);
7630   aSec.AddArgument (theBounds);
7631   //
7632   aSec.Perform();
7633   //
7634   // invalid vertices
7635   TopTools_IndexedMapOfShape aMVInv;
7636   // vertices to check additionally by classification relatively to solid
7637   TopTools_MapOfShape aMVCheckAdd;
7638   // collect parts for removal
7639   const BOPDS_PDS& pDS = aSec.PDS();
7640   //
7641   // check edge/edge intersections
7642   const BOPDS_VectorOfInterfEE& aEEs = pDS->InterfEE();
7643   Standard_Integer i, aNb = aEEs.Length();
7644   for (i = 0; i < aNb; ++i)
7645   {
7646     const BOPDS_InterfEE& aEE = aEEs (i);
7647     //
7648     const TopoDS_Shape& aE1 = pDS->Shape (aEE.Index1());
7649     const TopoDS_Shape& aE2 = pDS->Shape (aEE.Index2());
7650     //
7651     if (!aEE.HasIndexNew())
7652     {
7653       if (theMECheckExt.Contains (aE1) && (aEE.CommonPart().Type() == TopAbs_EDGE))
7654       {
7655         theMEInv.Add (aE1);
7656       }
7657       continue;
7658     }
7659     //
7660     if (myInvalidEdges.Contains (aE2))
7661     {
7662       theMEInv.Add (aE1);
7663     }
7664     //
7665     if (theMEInvOnArt.Contains (aE2))
7666     {
7667       // avoid checking of the vertices of the split edge intersected by
7668       // the invalid edge from artificial face
7669       TopoDS_Vertex aV1, aV2;
7670       TopExp::Vertices (TopoDS::Edge (aE2), aV1, aV2);
7671       if (aDMVE.Contains (aV1) && aDMVE.Contains (aV2))
7672       {
7673         continue;
7674       }
7675     }
7676     //
7677     // add vertices of all images of the edge from splits for checking
7678     const TopTools_ListOfShape& aLEOr = theDMEOr.Find (aE1);
7679     TopTools_ListIteratorOfListOfShape aItLEOr (aLEOr);
7680     for (; aItLEOr.More(); aItLEOr.Next())
7681     {
7682       const TopoDS_Shape& aEOr = aItLEOr.Value();
7683       //
7684       const TopTools_ListOfShape* pLEIm = theEImages.Seek (aEOr);
7685       if (!pLEIm)
7686         continue;
7687       TopTools_ListIteratorOfListOfShape aItLEIm (*pLEIm);
7688       for (; aItLEIm.More(); aItLEIm.Next())
7689       {
7690         const TopoDS_Shape& aEIm = aItLEIm.Value();
7691         //
7692         TopoDS_Iterator aItV (aEIm);
7693         for (; aItV.More(); aItV.Next())
7694         {
7695           const TopoDS_Shape& aV = aItV.Value();
7696           if (!theMVOld.Contains (aV))
7697           {
7698             aMVInv.Add (aV);
7699             aMVCheckAdd.Add (aV);
7700           }
7701         }
7702       }
7703     }
7704   }
7705   //
7706   // to avoid unnecessary filling of parts due to extra trim of the edges
7707   // process Edge/Edge interferences of type EDGE, i.e. common blocks and check
7708   // not the bounding vertices of the edges, but check the edge itself
7709   // to be lying on some face
7710   //
7711   // all common blocks are contained in the result of SECTION operation
7712   // between sets of edges
7713   const TopoDS_Shape& aSecR = aSec.Shape();
7714   //
7715   TopTools_IndexedMapOfShape aMSSec;
7716   TopExp::MapShapes (aSecR, aMSSec);
7717   //
7718   const TopTools_DataMapOfShapeListOfShape& anIm = aSec.Images();
7719   for (TopExp_Explorer aExp (theSplits, TopAbs_EDGE); aExp.More(); aExp.Next())
7720   {
7721     const TopoDS_Shape& aE = aExp.Current();
7722     if (aSec.IsDeleted (aE))
7723     {
7724       // no common blocks for this edge
7725       continue;
7726     }
7727     //
7728     const TopTools_ListOfShape* pLEIm = anIm.Seek (aE);
7729     if (!pLEIm)
7730     {
7731       // no splits, i.e. completely coincides with some edge from boundary
7732       continue;
7733     }
7734     //
7735     TopTools_ListIteratorOfListOfShape aItLEIm (*pLEIm);
7736     for (; aItLEIm.More(); aItLEIm.Next())
7737     {
7738       const TopoDS_Shape& aEIm = aItLEIm.Value();
7739       if (!aMSSec.Contains (aEIm))
7740       {
7741         // the edge included in section only partially.
7742         // the part not included in section may be excessive
7743         //
7744         // check vertices of this edge - if one of them is new
7745         // the edge might be removed
7746         TopoDS_Vertex aV1, aV2;
7747         TopExp::Vertices (TopoDS::Edge (aEIm), aV1, aV2);
7748         if (!theMVOld.Contains (aV1) || !theMVOld.Contains (aV2))
7749         {
7750           // add this edge for checking by making new vertex in the middle of the edge
7751           TopoDS_Vertex aV;
7752           Standard_Real f, l;
7753           const Handle(Geom_Curve)& aC = BRep_Tool::Curve (TopoDS::Edge (aEIm), f, l);
7754           BRep_Builder().MakeVertex (aV, aC->Value ((f + l) * 0.5), Precision::Confusion());
7755           // and adding this vertex for checking
7756           aDMVE.ChangeFromIndex (aDMVE.Add (aV, TopTools_ListOfShape())).Append (aE);
7757           aMVInv.Add (aV);
7758           break;
7759         }
7760       }
7761     }
7762   }
7763   //
7764   // Add for check also the edges created from common between splits
7765   // of offset faces edges not connected to any invalidity.
7766   // These edges may also accidentally fill some part.
7767   TopTools_MapIteratorOfMapOfShape aItM (theMECheckExt);
7768   for (; aItM.More(); aItM.Next())
7769   {
7770     const TopoDS_Shape& aE = aItM.Value();
7771     //
7772     // make new vertex in the middle of the edge
7773     TopoDS_Vertex aV;
7774     Standard_Real f, l;
7775     const Handle(Geom_Curve)& aC = BRep_Tool::Curve (TopoDS::Edge (aE), f, l);
7776     BRep_Builder().MakeVertex (aV, aC->Value ((f + l) * 0.5), Precision::Confusion());
7777     // add this vertex for checking
7778     aDMVE.ChangeFromIndex (aDMVE.Add (aV, TopTools_ListOfShape())).Append (aE);
7779     aMVInv.Add (aV);
7780   }
7781   //
7782   // add for check also the vertices connected only to new or old edges
7783   aNb = aDMVE.Extent();
7784   for (i = 1; i <= aNb; ++i)
7785   {
7786     const TopoDS_Shape& aV = aDMVE.FindKey (i);
7787     if (theMVOld.Contains (aV))
7788     {
7789       continue;
7790     }
7791     //
7792     Standard_Boolean bNew = Standard_False, bOld = Standard_False;
7793     const TopTools_ListOfShape& aLEx = aDMVE (i);
7794     TopTools_ListIteratorOfListOfShape aIt (aLEx);
7795     for (; aIt.More(); aIt.Next())
7796     {
7797       const TopoDS_Shape& aE = aIt.Value();
7798       if (theMECheckExt.Contains (aE))
7799       {
7800         continue;
7801       }
7802       //
7803       if (theMENew.Contains (aE))
7804       {
7805         bNew = Standard_True;
7806       }
7807       else
7808       {
7809         bOld = Standard_True;
7810       }
7811       //
7812       if (bNew && bOld)
7813       {
7814         break;
7815       }
7816     }
7817     //
7818     if (!bNew || !bOld)
7819     {
7820       aMVInv.Add (aV);
7821       aMVCheckAdd.Remove (aV);
7822     }
7823   }
7824   //
7825   // perform the checking of the vertices
7826   Standard_Integer iv, aNbIV = aMVInv.Extent();
7827   for (iv = 1; iv <= aNbIV; ++iv)
7828   {
7829     const TopoDS_Vertex& aV = TopoDS::Vertex (aMVInv (iv));
7830     if (theMVOld.Contains (aV))
7831     {
7832       continue;
7833     }
7834     //
7835     const TopTools_ListOfShape* pLEInv = aDMVE.Seek (aV);
7836     if (!pLEInv)
7837     {
7838       continue;
7839     }
7840     // find faces by the edges to check the vertex
7841     TopTools_IndexedMapOfShape aMF;
7842     TopTools_ListIteratorOfListOfShape aItLE (*pLEInv);
7843     for (; aItLE.More(); aItLE.Next())
7844     {
7845       const TopoDS_Shape& aE = aItLE.Value();
7846       const TopTools_ListOfShape& aLF = theMELF.Find (aE);
7847       TopTools_ListIteratorOfListOfShape aItLF (aLF);
7848       for (; aItLF.More(); aItLF.Next())
7849       {
7850         aMF.Add (aItLF.Value());
7851       }
7852     }
7853     //
7854     // check the vertex to belong to some split of the faces
7855     Standard_Boolean bInvalid = Standard_True;
7856     //
7857     Standard_Integer aNbF = aMF.Extent();
7858     for (i = 1; i <= aNbF && bInvalid; ++i)
7859     {
7860       const TopoDS_Face& aF = TopoDS::Face (aMF (i));
7861       const TopTools_ListOfShape& aLFIm = myOFImages.FindFromKey (aF);
7862       //
7863       TopTools_ListIteratorOfListOfShape aItLF (aLFIm);
7864       for (; aItLF.More() && bInvalid; aItLF.Next())
7865       {
7866         const TopoDS_Face& aFIm = TopoDS::Face (aItLF.Value());
7867         TopExp_Explorer aExp (aFIm, TopAbs_VERTEX);
7868         for (; aExp.More() && bInvalid; aExp.Next())
7869         {
7870           const TopoDS_Shape& aVF = aExp.Current();
7871           bInvalid = !aVF.IsSame (aV);
7872         }
7873       }
7874       //
7875       if (bInvalid)
7876       {
7877         Standard_Real U, V, aTol;
7878         Standard_Integer iStatus = myContext->ComputeVF (aV, aF, U, V, aTol);
7879         if (!iStatus)
7880         {
7881           // classify the point relatively faces
7882           gp_Pnt2d aP2d (U, V);
7883           aItLF.Initialize (aLFIm);
7884           for (; aItLF.More() && bInvalid; aItLF.Next())
7885           {
7886             const TopoDS_Face& aFIm = TopoDS::Face (aItLF.Value());
7887             bInvalid = !myContext->IsPointInOnFace (aFIm, aP2d);
7888           }
7889         }
7890       }
7891     }
7892     //
7893     if (bInvalid && aMVCheckAdd.Contains (aV))
7894     {
7895       // the vertex is invalid for all faces
7896       // check the same vertex for the solids
7897       const gp_Pnt& aP = BRep_Tool::Pnt (aV);
7898       Standard_Real aTolV = BRep_Tool::Tolerance (aV);
7899       //
7900       TopExp_Explorer aExpS (mySolids, TopAbs_SOLID);
7901       for (; aExpS.More() && bInvalid; aExpS.Next())
7902       {
7903         const TopoDS_Solid& aSol = TopoDS::Solid (aExpS.Current());
7904         BRepClass3d_SolidClassifier& aSC = myContext->SolidClassifier (aSol);
7905         aSC.Perform (aP, aTolV);
7906         bInvalid = (aSC.State() == TopAbs_OUT);
7907       }
7908     }
7909     //
7910     if (bInvalid)
7911     {
7912       theVertsToAvoid.Add (aV);
7913       aItLE.Initialize (*pLEInv);
7914       for (; aItLE.More(); aItLE.Next())
7915       {
7916         theMEInv.Add (aItLE.Value());
7917       }
7918     }
7919   }
7920 }
7921 
7922 //=======================================================================
7923 //function : FilterSplits
7924 //purpose  : Filter the images of edges from the invalid edges
7925 //=======================================================================
FilterSplits(const TopTools_ListOfShape & theLE,const TopTools_MapOfShape & theMEFilter,const Standard_Boolean theIsInv,TopTools_DataMapOfShapeListOfShape & theEImages,TopoDS_Shape & theSplits)7926 void BRepOffset_BuildOffsetFaces::FilterSplits (const TopTools_ListOfShape& theLE,
7927                                                 const TopTools_MapOfShape& theMEFilter,
7928                                                 const Standard_Boolean theIsInv,
7929                                                 TopTools_DataMapOfShapeListOfShape& theEImages,
7930                                                 TopoDS_Shape& theSplits)
7931 {
7932   TopoDS_Compound aSplits;
7933   BRep_Builder().MakeCompound (aSplits);
7934   TopTools_MapOfShape aMFence;
7935 
7936   TopTools_ListIteratorOfListOfShape aItLE (theLE);
7937   for (; aItLE.More(); aItLE.Next())
7938   {
7939     const TopoDS_Shape& aE = aItLE.Value();
7940     TopTools_ListOfShape* pLEIm = theEImages.ChangeSeek (aE);
7941     if (!pLEIm)
7942       continue;
7943 
7944     TopTools_ListIteratorOfListOfShape aItLEIm (*pLEIm);
7945     for (; aItLEIm.More();)
7946     {
7947       const TopoDS_Shape& aEIm = aItLEIm.Value();
7948       if (theMEFilter.Contains (aEIm) == theIsInv)
7949       {
7950         pLEIm->Remove (aItLEIm);
7951         continue;
7952       }
7953 
7954       if (aMFence.Add (aEIm))
7955         BRep_Builder().Add (aSplits, aEIm);
7956       aItLEIm.Next();
7957     }
7958 
7959     if (pLEIm->IsEmpty())
7960       theEImages.UnBind (aE);
7961   }
7962   theSplits = aSplits;
7963 }
7964 
7965 //=======================================================================
7966 //function : UpdateNewIntersectionEdges
7967 //purpose  : Updating the maps of images and origins of the offset edges
7968 //=======================================================================
UpdateNewIntersectionEdges(const TopTools_ListOfShape & theLE,const TopTools_DataMapOfShapeListOfShape & theMELF,const TopTools_DataMapOfShapeListOfShape & theEImages,TopTools_DataMapOfShapeListOfShape & theEETrim)7969 void BRepOffset_BuildOffsetFaces::UpdateNewIntersectionEdges (const TopTools_ListOfShape& theLE,
7970                                                               const TopTools_DataMapOfShapeListOfShape& theMELF,
7971                                                               const TopTools_DataMapOfShapeListOfShape& theEImages,
7972                                                               TopTools_DataMapOfShapeListOfShape& theEETrim)
7973 {
7974   TopTools_ListOfShape aLEImEmpty;
7975   TopTools_ListIteratorOfListOfShape aIt, aIt1;
7976   // update global maps of images and origins with new splits
7977   aIt.Initialize (theLE);
7978   for (; aIt.More(); aIt.Next())
7979   {
7980     const TopoDS_Shape& aE = aIt.Value();
7981     //
7982     if (!theEImages.IsBound (aE))
7983     {
7984       TopTools_ListOfShape* pLET = theEETrim.ChangeSeek (aE);
7985       if (!pLET)
7986       {
7987         continue;
7988       }
7989       //
7990       TopTools_ListIteratorOfListOfShape aItLET (*pLET);
7991       for (; aItLET.More();)
7992       {
7993         const TopoDS_Shape& aET = aItLET.Value();
7994         if (!myInvalidEdges.Contains (aET) && !myInvertedEdges.Contains (aET))
7995         {
7996           pLET->Remove (aItLET);
7997         }
7998         else
7999         {
8000           aItLET.Next();
8001         }
8002       }
8003       //
8004       if (pLET->IsEmpty())
8005       {
8006         continue;
8007       }
8008     }
8009     // new images
8010     const TopTools_ListOfShape& aLENew =
8011       theEImages.IsBound (aE) ? theEImages.Find (aE) : aLEImEmpty;
8012     //
8013     // save connection to untrimmed edge for the next steps
8014     aIt1.Initialize (aLENew);
8015     for (; aIt1.More(); aIt1.Next())
8016     {
8017       const TopoDS_Shape& aET = aIt1.Value();
8018       myETrimEInf->Bind (aET, aE);
8019       myModifiedEdges.Add (aET);
8020     }
8021     //
8022     // check if it is existing edge
8023     if (!theEETrim.IsBound (aE))
8024     {
8025       const TopTools_ListOfShape& aLF = theMELF.Find (aE);
8026       // the edge is new
8027       // add this edge to AsDes
8028       aIt1.Initialize (aLF);
8029       for (; aIt1.More(); aIt1.Next())
8030       {
8031         const TopoDS_Shape& aF = aIt1.Value();
8032         myAsDes->Add (aF, aE);
8033       }
8034       //
8035       // add aE to the images
8036       myOEImages.Bind (aE, aLENew);
8037       myModifiedEdges.Add (aE);
8038       //
8039       // add to origins
8040       TopTools_ListIteratorOfListOfShape aItNew (aLENew);
8041       for (; aItNew.More(); aItNew.Next())
8042       {
8043         const TopoDS_Shape& aENew = aItNew.Value();
8044         if (myOEOrigins.IsBound (aENew))
8045         {
8046           TopTools_ListOfShape& aEOrigins = myOEOrigins.ChangeFind (aENew);
8047           AppendToList (aEOrigins, aE);
8048         }
8049         else
8050         {
8051           TopTools_ListOfShape aEOrigins;
8052           aEOrigins.Append (aE);
8053           myOEOrigins.Bind (aENew, aEOrigins);
8054         }
8055       }
8056       //
8057       // update connection to initial origins
8058       if (myEdgesOrigins->IsBound (aE))
8059       {
8060         const TopTools_ListOfShape& aLEOrInit = myEdgesOrigins->Find (aE);
8061         aIt1.Initialize (aLENew);
8062         for (; aIt1.More(); aIt1.Next())
8063         {
8064           const TopoDS_Shape& aENew = aIt1.Value();
8065           if (myEdgesOrigins->IsBound (aENew))
8066           {
8067             TopTools_ListOfShape& aLENewOr = myEdgesOrigins->ChangeFind (aENew);
8068             TopTools_ListIteratorOfListOfShape aItOrInit (aLEOrInit);
8069             for (; aItOrInit.More(); aItOrInit.Next())
8070             {
8071               const TopoDS_Shape& aEOr = aItOrInit.Value();
8072               AppendToList (aLENewOr, aEOr);
8073             }
8074           }
8075           else
8076           {
8077             myEdgesOrigins->Bind (aENew, aLEOrInit);
8078           }
8079         }
8080       }
8081       //
8082       continue;
8083     }
8084     //
8085     // old images
8086     const TopTools_ListOfShape& aLEOld = theEETrim.Find (aE);
8087     //
8088     // list of initial origins
8089     TopTools_ListOfShape anInitOrigins;
8090     //
8091     // it is necessary to replace the old edges with new ones
8092     aIt1.Initialize (aLEOld);
8093     for (; aIt1.More(); aIt1.Next())
8094     {
8095       const TopoDS_Shape& aEOld = aIt1.Value();
8096       //
8097       if (myOEOrigins.IsBound (aEOld))
8098       {
8099         // get its origins
8100         const TopTools_ListOfShape& aEOrigins = myOEOrigins.Find (aEOld);
8101         //
8102         TopTools_ListIteratorOfListOfShape aItOr (aEOrigins);
8103         for (; aItOr.More(); aItOr.Next())
8104         {
8105           const TopoDS_Shape& aEOr = aItOr.Value();
8106           //
8107           myModifiedEdges.Add (aEOr);
8108           //
8109           TopTools_ListOfShape& aEImages = myOEImages.ChangeFind (aEOr);
8110           //
8111           // remove old edge from images
8112           TopTools_ListIteratorOfListOfShape aItIm (aEImages);
8113           for (; aItIm.More(); )
8114           {
8115             const TopoDS_Shape& aEIm = aItIm.Value();
8116             if (aEIm.IsSame (aEOld))
8117             {
8118               aEImages.Remove (aItIm);
8119             }
8120             else
8121             {
8122               aItIm.Next();
8123             }
8124           }
8125           //
8126           // add new images
8127           TopTools_ListIteratorOfListOfShape aItNew (aLENew);
8128           for (; aItNew.More(); aItNew.Next())
8129           {
8130             const TopoDS_Shape& aENew = aItNew.Value();
8131             AppendToList (aEImages, aENew);
8132             if (myOEOrigins.IsBound (aENew))
8133             {
8134               TopTools_ListOfShape& aENewOrigins = myOEOrigins.ChangeFind (aENew);
8135               AppendToList (aENewOrigins, aEOr);
8136             }
8137             else
8138             {
8139               TopTools_ListOfShape aENewOrigins;
8140               aENewOrigins.Append (aEOr);
8141               myOEOrigins.Bind (aENew, aENewOrigins);
8142             }
8143           }
8144         }
8145       }
8146       else
8147       {
8148         // add to images
8149         myOEImages.Bind (aEOld, aLENew);
8150         //
8151         myModifiedEdges.Add (aEOld);
8152         //
8153         // add to origins
8154         TopTools_ListIteratorOfListOfShape aItNew (aLENew);
8155         for (; aItNew.More(); aItNew.Next())
8156         {
8157           const TopoDS_Shape& aENew = aItNew.Value();
8158           if (myOEOrigins.IsBound (aENew))
8159           {
8160             TopTools_ListOfShape& aEOrigins = myOEOrigins.ChangeFind (aENew);
8161             AppendToList (aEOrigins, aEOld);
8162           }
8163           else
8164           {
8165             TopTools_ListOfShape aEOrigins;
8166             aEOrigins.Append (aEOld);
8167             myOEOrigins.Bind (aENew, aEOrigins);
8168           }
8169         }
8170       }
8171       //
8172       // update connection to initial shape
8173       if (myEdgesOrigins->IsBound (aEOld))
8174       {
8175         const TopTools_ListOfShape& aLEOrInit = myEdgesOrigins->Find (aEOld);
8176         TopTools_ListIteratorOfListOfShape aItEOrInit (aLEOrInit);
8177         for (; aItEOrInit.More(); aItEOrInit.Next())
8178         {
8179           const TopoDS_Shape& aEOrInit = aItEOrInit.Value();
8180           AppendToList (anInitOrigins, aEOrInit);
8181         }
8182       }
8183     }
8184     //
8185     if (anInitOrigins.Extent())
8186     {
8187       TopTools_ListIteratorOfListOfShape aItNew (aLENew);
8188       for (; aItNew.More(); aItNew.Next())
8189       {
8190         const TopoDS_Shape& aENew = aItNew.Value();
8191         if (myEdgesOrigins->IsBound (aENew))
8192         {
8193           TopTools_ListOfShape& aLENewOr = myEdgesOrigins->ChangeFind (aENew);
8194           TopTools_ListIteratorOfListOfShape aItOrInit (anInitOrigins);
8195           for (; aItOrInit.More(); aItOrInit.Next())
8196           {
8197             const TopoDS_Shape& aEOr = aItOrInit.Value();
8198             AppendToList (aLENewOr, aEOr);
8199           }
8200         }
8201         else
8202         {
8203           myEdgesOrigins->Bind (aENew, anInitOrigins);
8204         }
8205       }
8206     }
8207   }
8208 }
8209 
8210 //=======================================================================
8211 //function : FillGaps
8212 //purpose  : Fill possible gaps (holes) in the splits of the offset faces
8213 //=======================================================================
FillGaps(const Message_ProgressRange & theRange)8214 void BRepOffset_BuildOffsetFaces::FillGaps (const Message_ProgressRange& theRange)
8215 {
8216   Standard_Integer aNbF = myOFImages.Extent();
8217   if (!aNbF)
8218     return;
8219 
8220   Message_ProgressScope aPS (theRange, "Filling gaps", 2 * aNbF);
8221 
8222   // Check the splits of offset faces on the free edges and fill the gaps (holes)
8223   // in created splits, otherwise the closed volume will not be possible to create.
8224 
8225   // Map the splits of faces to find free edges
8226   TopTools_IndexedDataMapOfShapeListOfShape anEFMap;
8227   for (Standard_Integer i = 1; i <= aNbF; ++i, aPS.Next())
8228   {
8229     if (!aPS.More())
8230     {
8231       return;
8232     }
8233 
8234     TopTools_ListIteratorOfListOfShape itLF (myOFImages (i));
8235     for (; itLF.More(); itLF.Next())
8236       TopExp::MapShapesAndAncestors (itLF.Value(), TopAbs_EDGE, TopAbs_FACE, anEFMap);
8237   }
8238 
8239   // Analyze images of each offset face on the presence of free edges
8240   // and try to fill the holes
8241   for (Standard_Integer i = 1; i <= aNbF; ++i, aPS.Next())
8242   {
8243     if (!aPS.More())
8244     {
8245       return;
8246     }
8247 
8248     TopTools_ListOfShape& aLFImages = myOFImages (i);
8249     if (aLFImages.IsEmpty())
8250       continue;
8251 
8252     // Collect all edges from the splits
8253     TopoDS_Compound anEdges;
8254     BRep_Builder().MakeCompound (anEdges);
8255 
8256     // Collect all free edges into a map with reverted orientation
8257     TopTools_MapOfOrientedShape aFreeEdgesMap;
8258     TopTools_ListIteratorOfListOfShape itLF (aLFImages);
8259     for (; itLF.More(); itLF.Next())
8260     {
8261       const TopoDS_Shape& aFIm = itLF.Value();
8262       TopExp_Explorer anExpE (aFIm, TopAbs_EDGE);
8263       for (; anExpE.More(); anExpE.Next())
8264       {
8265         const TopoDS_Shape& aE = anExpE.Current();
8266         if (aE.Orientation() != TopAbs_FORWARD &&
8267             aE.Orientation() != TopAbs_REVERSED)
8268           // Skip internals
8269           continue;
8270 
8271         const TopTools_ListOfShape& aLF = anEFMap.FindFromKey (aE);
8272         if (aLF.Extent() == 1)
8273           aFreeEdgesMap.Add (aE.Reversed());
8274 
8275         BRep_Builder().Add (anEdges, aE);
8276       }
8277     }
8278 
8279     if (aFreeEdgesMap.IsEmpty())
8280       // No free edges
8281       continue;
8282 
8283     // Free edges are found - fill the gaps by creating new splits
8284     // of the face using these free edges
8285     const TopoDS_Shape& aF = myOFImages.FindKey (i);
8286 
8287     // Build new splits using all kept edges and among new splits
8288     // find those containing free edges
8289     TopTools_ListOfShape aLFNew;
8290     TopTools_DataMapOfShapeShape aDummy;
8291 
8292     BuildSplitsOfFace (TopoDS::Face (aF), anEdges, aDummy, aLFNew);
8293 
8294     // Find faces filling holes
8295     itLF.Initialize (aLFNew);
8296     for (; itLF.More(); itLF.Next())
8297     {
8298       const TopoDS_Shape& aFNew = itLF.Value();
8299       TopExp_Explorer anExpE (aFNew, TopAbs_EDGE);
8300       for (; anExpE.More(); anExpE.Next())
8301       {
8302         const TopoDS_Shape& aE = anExpE.Current();
8303         if (aFreeEdgesMap.Contains (aE))
8304         {
8305           // Add face to splits
8306           aLFImages.Append (aFNew);
8307           break;
8308         }
8309       }
8310     }
8311   }
8312 }
8313 
8314 //=======================================================================
8315 //function : FillHistory
8316 //purpose  : Saving obtained results in history tools
8317 //=======================================================================
FillHistory()8318 void BRepOffset_BuildOffsetFaces::FillHistory()
8319 {
8320   Standard_Integer aNbF = myOFImages.Extent();
8321   if (!aNbF)
8322   {
8323     return;
8324   }
8325 
8326 #ifdef OFFSET_DEBUG
8327   // Build compound of faces to see preliminary result
8328   TopoDS_Compound aDFaces;
8329   BRep_Builder().MakeCompound (aDFaces);
8330 #endif
8331 
8332   // Map of kept edges
8333   TopTools_IndexedMapOfShape anEdgesMap;
8334 
8335   // Fill history for faces
8336   for (Standard_Integer i = 1; i <= aNbF; ++i)
8337   {
8338     const TopTools_ListOfShape& aLFImages = myOFImages (i);
8339     if (aLFImages.IsEmpty())
8340     {
8341       continue;
8342     }
8343 
8344     // Add the splits to history map
8345     const TopoDS_Shape& aF = myOFImages.FindKey (i);
8346     if (myImage->HasImage (aF))
8347       myImage->Add (aF, aLFImages);
8348     else
8349       myImage->Bind (aF, aLFImages);
8350 
8351     // Collect edges from splits
8352     TopTools_ListIteratorOfListOfShape itLF (aLFImages);
8353     for (; itLF.More(); itLF.Next())
8354     {
8355       const TopoDS_Shape& aFIm = itLF.Value();
8356       TopExp::MapShapes (aFIm, TopAbs_EDGE, anEdgesMap);
8357 
8358 #ifdef OFFSET_DEBUG
8359       BRep_Builder().Add (aDFaces, aFIm);
8360 #endif
8361     }
8362   }
8363 
8364   // Fill history for edges (iteration by the map is safe because the
8365   // order is not important here)
8366   TopTools_DataMapIteratorOfDataMapOfShapeListOfShape aItEIm (myOEImages);
8367   for (; aItEIm.More(); aItEIm.Next())
8368   {
8369     const TopoDS_Shape& aE = aItEIm.Key();
8370     const TopTools_ListOfShape& aLEIm = aItEIm.Value();
8371 
8372     Standard_Boolean bHasImage = myImage->HasImage (aE);
8373     TopTools_ListIteratorOfListOfShape aItLE (aLEIm);
8374     for (; aItLE.More(); aItLE.Next())
8375     {
8376       const TopoDS_Shape& aEIm = aItLE.Value();
8377       if (anEdgesMap.Contains (aEIm))
8378       {
8379         if (bHasImage)
8380         {
8381           myImage->Add (aE, aEIm);
8382         }
8383         else
8384         {
8385           myImage->Bind (aE, aEIm);
8386           bHasImage = Standard_True;
8387         }
8388       }
8389     }
8390   }
8391 }
8392 
8393 
8394 //=======================================================================
8395 //function : BuildSplitsOfTrimmedFaces
8396 //purpose  : Building splits of already trimmed faces
8397 //=======================================================================
BuildSplitsOfTrimmedFaces(const TopTools_ListOfShape & theLF,const Handle (BRepAlgo_AsDes)& theAsDes,BRepAlgo_Image & theImage,const Message_ProgressRange & theRange)8398 void BRepOffset_MakeOffset::BuildSplitsOfTrimmedFaces (const TopTools_ListOfShape& theLF,
8399                                                        const Handle(BRepAlgo_AsDes)& theAsDes,
8400                                                        BRepAlgo_Image& theImage,
8401                                                        const Message_ProgressRange& theRange)
8402 {
8403   BRepOffset_BuildOffsetFaces aBFTool (theImage);
8404   aBFTool.SetFaces (theLF);
8405   aBFTool.SetAsDesInfo (theAsDes);
8406   aBFTool.BuildSplitsOfTrimmedFaces (theRange);
8407 }
8408 
8409 //=======================================================================
8410 //function : BuildSplitsOfExtendedFaces
8411 //purpose  : Building splits of not-trimmed offset faces.
8412 //           For the cases in which invalidity will be found,
8413 //           these invalidities will be rebuilt.
8414 //=======================================================================
BuildSplitsOfExtendedFaces(const TopTools_ListOfShape & theLF,const BRepOffset_Analyse & theAnalyse,const Handle (BRepAlgo_AsDes)& theAsDes,TopTools_DataMapOfShapeListOfShape & theEdgesOrigins,TopTools_DataMapOfShapeShape & theFacesOrigins,TopTools_DataMapOfShapeShape & theETrimEInf,BRepAlgo_Image & theImage,const Message_ProgressRange & theRange)8415 void BRepOffset_MakeOffset::BuildSplitsOfExtendedFaces (const TopTools_ListOfShape& theLF,
8416                                                         const BRepOffset_Analyse& theAnalyse,
8417                                                         const Handle(BRepAlgo_AsDes)& theAsDes,
8418                                                         TopTools_DataMapOfShapeListOfShape& theEdgesOrigins,
8419                                                         TopTools_DataMapOfShapeShape& theFacesOrigins,
8420                                                         TopTools_DataMapOfShapeShape& theETrimEInf,
8421                                                         BRepAlgo_Image& theImage,
8422                                                         const Message_ProgressRange& theRange)
8423 {
8424   BRepOffset_BuildOffsetFaces aBFTool (theImage);
8425   aBFTool.SetFaces (theLF);
8426   aBFTool.SetAsDesInfo (theAsDes);
8427   aBFTool.SetAnalysis (theAnalyse);
8428   aBFTool.SetEdgesOrigins (theEdgesOrigins);
8429   aBFTool.SetFacesOrigins (theFacesOrigins);
8430   aBFTool.SetInfEdges (theETrimEInf);
8431   aBFTool.BuildSplitsOfExtendedFaces (theRange);
8432 }
8433