Salome HOME
Mantis issue 0021191: GlueEdges and GlueFaces problem with tolerance 1. A fix by...
[modules/geom.git] / src / NMTTools / NMTTools_Tools.cxx
1 // Copyright (C) 2007-2011  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21
22 // File:        NMTTools_Tools.cxx
23 // Created:     Mon Dec  8 10:35:15 2003
24 // Author:      Peter KURNEV
25
26 #include <NMTTools_Tools.ixx>
27
28 #include <Basics_OCCTVersion.hxx>
29
30 #include <NMTTools_ListIteratorOfListOfCoupleOfShape.hxx>
31 #include <NMTTools_IndexedDataMapOfShapeIndexedMapOfShape.hxx>
32 #include <NMTTools_CoupleOfShape.hxx>
33
34 #include <TopoDS.hxx>
35 #include <TopoDS_Vertex.hxx>
36 #include <TopoDS_Shape.hxx>
37 #include <TopoDS_Edge.hxx>
38 #include <TopoDS_Iterator.hxx>
39
40 #include <TopExp.hxx>
41 #include <TopExp_Explorer.hxx>
42
43 #include <TopTools_MapOfShape.hxx>
44 #include <TopTools_MapIteratorOfMapOfShape.hxx>
45 #include <TopTools_IndexedMapOfShape.hxx>
46 #include <TopTools_ListIteratorOfListOfShape.hxx>
47
48 #include <BRep_Tool.hxx>
49 #include <BRep_Builder.hxx>
50 #include <BRepTools.hxx>
51 #include <BRepLib.hxx>
52
53 #include <BOPTColStd_IndexedDataMapOfIntegerIndexedMapOfInteger.hxx>
54 #include <BOPTColStd_IndexedDataMapOfIntegerIndexedMapOfInteger.hxx>
55
56 #include <BOPTools_VVInterference.hxx>
57 #include <BOPTools_SSInterference.hxx>
58 #include <BOPTools_Tools2D.hxx>
59 #include <BOPTools_Tools3D.hxx>
60 #include <BOPTools_Tools.hxx>
61
62 #include <Geom_Curve.hxx>
63 #include <Geom_TrimmedCurve.hxx>
64 #include <Geom_Surface.hxx>
65 #include <GeomAPI_ProjectPointOnSurf.hxx>
66 #include <Geom2d_Curve.hxx>
67
68 #include <TColStd_IndexedMapOfInteger.hxx>
69
70 #include <gp_Pnt.hxx>
71 #include <gp_XYZ.hxx>
72 #include <gp_Pnt2d.hxx>
73
74 static
75   void ProcessBlock(const Standard_Integer iV,
76                     const BOPTColStd_IndexedDataMapOfIntegerIndexedMapOfInteger& aMCV,
77                     TColStd_IndexedMapOfInteger& aProcessed,
78                     TColStd_IndexedMapOfInteger& aChain);
79 static
80   void ProcessBlock(const TopoDS_Shape& aF,
81                     const NMTTools_IndexedDataMapOfShapeIndexedMapOfShape& aMCV,
82                     TopTools_IndexedMapOfShape& aProcessed,
83                     TopTools_IndexedMapOfShape& aChain);
84
85 //modified by NIZNHY-PKV Thu Nov 16 10:46:53 2006f SKL/PartC5
86 //=======================================================================
87 // function: UpdateEdge
88 // purpose:
89 //=======================================================================
90   void  NMTTools_Tools::UpdateEdge(const TopoDS_Edge& aE,
91                                    const Standard_Real aTolR)
92 {
93   Standard_Real aTolE, aTolES, aTolV;
94   TopoDS_Iterator aIt;
95   BRep_Builder aBB;
96   //
97   aTolE=BRep_Tool::Tolerance(aE);
98   aTolES=Max(aTolR, aTolE);
99   aBB.UpdateEdge(aE, aTolES);
100   //
101   aIt.Initialize(aE);
102   for (; aIt.More(); aIt.Next()) {
103     const TopoDS_Vertex& aV=TopoDS::Vertex(aIt.Value());
104     aTolV=BRep_Tool::Tolerance(aV);
105     if (aTolV<aTolES) {
106        aBB.UpdateVertex(aV, aTolES);
107     }
108   }
109 }
110 //=======================================================================
111 // function: MakePCurve
112 // purpose:
113 //=======================================================================
114   void  NMTTools_Tools::MakePCurve(const TopoDS_Edge& aE,
115                                     const TopoDS_Face& aF,
116                                     const Handle(Geom2d_Curve)& aC2Dx1)
117 {
118   Standard_Real aTolE, aT1, aT2, aOutFirst, aOutLast, aOutTol;
119   Handle(Geom2d_Curve) aC2D, aC2DA;
120   TopoDS_Face aFFWD;
121   BRep_Builder aBB;
122   //
123   aFFWD=aF;
124   aFFWD.Orientation(TopAbs_FORWARD);
125   //
126   aTolE=BRep_Tool::Tolerance(aE);
127   //
128   const Handle(Geom_Curve)& aC3DE=BRep_Tool::Curve(aE, aT1, aT2);
129   Handle(Geom_TrimmedCurve)aC3DETrim=new Geom_TrimmedCurve(aC3DE, aT1, aT2);
130   //
131   aC2D=aC2Dx1;
132   if (aC2D.IsNull()) { // ?
133     BOPTools_Tools2D::BuildPCurveForEdgeOnFace(aE, aFFWD);
134     BOPTools_Tools2D::CurveOnSurface(aE, aFFWD, aC2D, aOutFirst, aOutLast, aOutTol, Standard_True);
135   }
136   //
137   if (aC3DE->IsPeriodic()) {
138     BOPTools_Tools2D::AdjustPCurveOnFace(aFFWD, aT1, aT2,  aC2D, aC2DA);
139   }
140   else {
141     BOPTools_Tools2D::AdjustPCurveOnFace(aFFWD, aC3DETrim, aC2D, aC2DA);
142   }
143   //
144   aBB.UpdateEdge(aE, aC2DA, aFFWD, aTolE);
145   BRepLib::SameParameter(aE);
146 }
147 /*
148 //=======================================================================
149 // function: MakePCurve
150 // purpose:
151 //=======================================================================
152   void  NMTTools_Tools::MakePCurve(const TopoDS_Edge& aE,
153                                    const TopoDS_Face& aF,
154                                    const Handle(Geom2d_Curve)& aC2Dx,
155                                    const Standard_Real aTolR2D)
156 {
157   Standard_Integer k, aNbV;
158   Standard_Real aTolEdge, aTolFact, aTolV, aTolVmax;
159   Standard_Real aTFirst, aTLast, aOutFirst, aOutLast, aOutTol;
160   TopoDS_Face aFFWD;
161   TopTools_IndexedMapOfShape aVMap;
162   BRep_Builder aBB;
163   //
164   aFFWD=aF;
165   aFFWD.Orientation(TopAbs_FORWARD);
166   //
167   aTolEdge=BRep_Tool::Tolerance(aE);
168   aTolFact=Max(aTolEdge, aTolR2D);
169   //
170   TopExp::MapShapes(aE, TopAbs_VERTEX, aVMap);
171   //
172   aTolVmax=-1.;
173   aNbV=aVMap.Extent();
174   for (k=1; k<=aNbV; ++k) {
175     const TopoDS_Vertex& aV=TopoDS::Vertex(aVMap(k));
176     aTolV=BRep_Tool::Tolerance(aV);
177     if (aTolV>aTolVmax) {
178       aTolVmax=aTolV;
179     }
180   }
181   //
182   if (aTolFact>aTolVmax) {
183     aTolFact=aTolVmax;
184   }
185   //
186   const Handle(Geom_Curve)& aC3DE=BRep_Tool::Curve(aE, aTFirst, aTLast);
187   Handle(Geom_TrimmedCurve)aC3DETrim=new Geom_TrimmedCurve(aC3DE, aTFirst, aTLast);
188   //
189   Handle(Geom2d_Curve) aC2D, aC2DA;
190   //
191   aC2D=aC2Dx;
192   if (aC2D.IsNull()) {
193     BOPTools_Tools2D::BuildPCurveForEdgeOnFace(aE, aFFWD);
194     BOPTools_Tools2D::CurveOnSurface(aE, aFFWD, aC2D, aOutFirst, aOutLast, aOutTol, Standard_True);
195   }
196   if (aC3DE->IsPeriodic()) {
197     BOPTools_Tools2D::AdjustPCurveOnFace(aFFWD, aTFirst, aTLast,  aC2D, aC2DA);
198   }
199   else {
200     BOPTools_Tools2D::AdjustPCurveOnFace(aFFWD, aC3DETrim, aC2D, aC2DA);
201   }
202   //
203   aBB.UpdateEdge(aE, aC2DA, aFFWD, aTolFact);
204   BRepLib::SameParameter(aE);
205 }
206 */
207 //modified by NIZNHY-PKV Thu Nov 16 10:46:55 2006t
208 //=======================================================================
209 // function: IsSplitInOnFace
210 // purpose:
211 //=======================================================================
212   Standard_Boolean NMTTools_Tools::IsSplitInOnFace(const TopoDS_Edge& aE,
213                                                    const TopoDS_Face& aF,
214 #if OCC_VERSION_LARGE > 0x06050200
215                                                    const Handle(IntTools_Context)& aContext)
216 #else
217                                                    IntTools_Context& aContext)
218 #endif
219 {
220   Standard_Boolean bFlag;
221   Standard_Real aT, aTolE, aTolF, aTol, aDist, aU, aV;
222   gp_Pnt aP;
223   gp_Pnt2d aP2D;
224   //
225   aTolE=BRep_Tool::Tolerance(aE);
226   aTolF=BRep_Tool::Tolerance(aF);
227   aTol=aTolE+aTolF;
228   //
229 #if OCC_VERSION_LARGE > 0x06050200
230   GeomAPI_ProjectPointOnSurf& aProjector=aContext->ProjPS(aF);
231 #else
232   GeomAPI_ProjectPointOnSurf& aProjector=aContext.ProjPS(aF);
233 #endif
234   //
235   aT=BOPTools_Tools2D::IntermediatePoint(aE);
236   BOPTools_Tools::PointOnEdge(aE, aT, aP);
237   //
238   aProjector.Perform(aP);
239   bFlag=aProjector.IsDone();
240   if (!bFlag) {
241     return bFlag;
242   }
243   //
244   aDist=aProjector.LowerDistance();
245   bFlag=(aDist <= aTol);
246   if (!bFlag) {
247     return bFlag;
248   }
249   //
250   aProjector.LowerDistanceParameters(aU, aV);
251   aP2D.SetCoord(aU, aV);
252 #if OCC_VERSION_LARGE > 0x06050200
253   bFlag=aContext->IsPointInOnFace (aF, aP2D);
254 #else
255   bFlag=aContext.IsPointInOnFace (aF, aP2D);
256 #endif
257   return bFlag;
258 }
259 //=======================================================================
260 // function: NMTTools_Tools::MakeNewVertex
261 // purpose :
262 //=======================================================================
263   void NMTTools_Tools::MakeNewVertex(const TopTools_ListOfShape& aLVs,
264                                      TopoDS_Vertex& aNewVertex)
265 {
266   Standard_Integer aNb;
267   Standard_Real aTi, aDi, aDmax=-1.e5;
268   gp_Pnt aPi, aP;
269   gp_XYZ aXYZ(0.,0.,0.), aXYZi;
270   TopTools_ListIteratorOfListOfShape anIt;
271   //
272   aNb=aLVs.Extent();
273   if (!aNb) {
274     return;
275   }
276   //
277   anIt.Initialize(aLVs);
278   for (; anIt.More(); anIt.Next()) {
279     TopoDS_Vertex aVi=TopoDS::Vertex(anIt.Value());
280     aPi=BRep_Tool::Pnt(aVi);
281     aXYZi=aPi.XYZ();
282     aXYZ=aXYZ+aXYZi;
283   }
284   //
285   aXYZ.Divide((Standard_Real)aNb);
286   aP.SetXYZ(aXYZ);
287   //
288   anIt.Initialize(aLVs);
289   for (; anIt.More(); anIt.Next()) {
290     TopoDS_Vertex aVi=TopoDS::Vertex(anIt.Value());
291     aPi=BRep_Tool::Pnt(aVi);
292     aTi=BRep_Tool::Tolerance(aVi);
293     aDi=aP.Distance(aPi);
294     aDi=aDi+aTi;
295     if (aDi > aDmax) {
296       aDmax=aDi;
297     }
298   }
299   BRep_Builder aBB;
300   aBB.MakeVertex (aNewVertex, aP, aDmax);
301 }
302 //=======================================================================
303 // function: FindChains
304 // purpose :
305 //=======================================================================
306   void NMTTools_Tools::FindChains(const BOPTools_CArray1OfSSInterference& FFs,
307                                   BOPTColStd_IndexedDataMapOfIntegerIndexedMapOfInteger& aMapChains)
308 {
309   Standard_Boolean bIsTangentFaces;
310   Standard_Integer j, aNb, anIndex1, anIndex2;
311   BOPTColStd_IndexedDataMapOfIntegerIndexedMapOfInteger aMCV;
312   //
313   aNb=FFs.Extent();
314   for (j=1; j<=aNb; ++j) {
315     const BOPTools_SSInterference& aFF=FFs(j);
316     //
317     bIsTangentFaces=aFF.IsTangentFaces();
318     if (!bIsTangentFaces) {
319       continue;
320     }
321     //
322     aFF.Indices(anIndex1, anIndex2);
323     //
324     if (aMCV.Contains(anIndex1)) {
325       TColStd_IndexedMapOfInteger& aMV=aMCV.ChangeFromKey(anIndex1);
326       aMV.Add(anIndex1);
327       aMV.Add(anIndex2);
328     }
329     else {
330       TColStd_IndexedMapOfInteger aMV;
331       aMV.Add(anIndex1);
332       aMV.Add(anIndex2);
333       aMCV.Add(anIndex1, aMV);
334     }
335     //
336     if (aMCV.Contains(anIndex2)) {
337       TColStd_IndexedMapOfInteger& aMV=aMCV.ChangeFromKey(anIndex2);
338       aMV.Add(anIndex1);
339       aMV.Add(anIndex2);
340     }
341     else {
342       TColStd_IndexedMapOfInteger aMV;
343       aMV.Add(anIndex1);
344       aMV.Add(anIndex2);
345       aMCV.Add(anIndex2, aMV);
346     }
347   }
348   NMTTools_Tools::FindChains(aMCV, aMapChains);
349 }
350 //=======================================================================
351 // function: FindChains
352 // purpose :
353 //=======================================================================
354   void NMTTools_Tools::FindChains(const BOPTools_CArray1OfVVInterference& VVs,
355                                   BOPTColStd_IndexedDataMapOfIntegerIndexedMapOfInteger& aMapChains)
356 {
357   Standard_Integer j, aNb, anIndex1, anIndex2;
358   BOPTColStd_IndexedDataMapOfIntegerIndexedMapOfInteger aMCV;
359   //
360   aNb=VVs.Extent();
361   for (j=1; j<=aNb; ++j) {
362     const BOPTools_VVInterference& VV=VVs(j);
363     VV.Indices(anIndex1, anIndex2);
364     //
365     if (aMCV.Contains(anIndex1)) {
366       TColStd_IndexedMapOfInteger& aMV=aMCV.ChangeFromKey(anIndex1);
367       aMV.Add(anIndex1);
368       aMV.Add(anIndex2);
369     }
370     else {
371       TColStd_IndexedMapOfInteger aMV;
372       aMV.Add(anIndex1);
373       aMV.Add(anIndex2);
374       aMCV.Add(anIndex1, aMV);
375     }
376     //
377     if (aMCV.Contains(anIndex2)) {
378       TColStd_IndexedMapOfInteger& aMV=aMCV.ChangeFromKey(anIndex2);
379       aMV.Add(anIndex1);
380       aMV.Add(anIndex2);
381     }
382     else {
383       TColStd_IndexedMapOfInteger aMV;
384       aMV.Add(anIndex1);
385       aMV.Add(anIndex2);
386       aMCV.Add(anIndex2, aMV);
387     }
388   }
389   NMTTools_Tools::FindChains(aMCV, aMapChains);
390 }
391
392 //=======================================================================
393 // function: FindChains
394 // purpose :
395 //=======================================================================
396   void NMTTools_Tools::FindChains(const BOPTColStd_IndexedDataMapOfIntegerIndexedMapOfInteger& aMCV,
397                                   BOPTColStd_IndexedDataMapOfIntegerIndexedMapOfInteger& aMapChains)
398 {
399   Standard_Integer  i, j, aNbCV, aNbV, iV, iVx;
400   TColStd_IndexedMapOfInteger aProcessed, aChain;
401   //
402   aNbCV=aMCV.Extent();
403   for (i=1; i<=aNbCV; ++i) {
404     iV=aMCV.FindKey(i);
405     if (aProcessed.Contains(iV)) {
406       continue;
407     }
408     //
409     aProcessed.Add(iV);
410     aChain.Add(iV);
411     //
412     const TColStd_IndexedMapOfInteger& aMV=aMCV(i);
413     aNbV=aMV.Extent();
414     for (j=1; j<=aNbV; ++j) {
415       iVx=aMV(j);
416       ProcessBlock(iVx, aMCV, aProcessed, aChain);
417     }
418     aMapChains.Add(i, aChain);
419     aChain.Clear();
420   }
421 }
422 //=======================================================================
423 // function: ProcessBlock
424 // purpose:
425 //=======================================================================
426 void ProcessBlock(const Standard_Integer iV,
427                   const BOPTColStd_IndexedDataMapOfIntegerIndexedMapOfInteger& aMCV,
428                   TColStd_IndexedMapOfInteger& aProcessed,
429                   TColStd_IndexedMapOfInteger& aChain)
430 {
431   Standard_Integer j, aNbV, iVx;
432   //
433   if (aProcessed.Contains(iV)) {
434     return;
435   }
436   aProcessed.Add(iV);
437   aChain.Add(iV);
438   //
439   const TColStd_IndexedMapOfInteger& aMV=aMCV.FindFromKey(iV);
440   aNbV=aMV.Extent();
441   for (j=1; j<=aNbV; ++j) {
442     iVx=aMV(j);
443     ProcessBlock(iVx, aMCV, aProcessed, aChain);
444   }
445 }
446 //=======================================================================
447 // function: AreFacesSameDomain
448 // purpose :
449 //=======================================================================
450   Standard_Boolean NMTTools_Tools::AreFacesSameDomain(const TopoDS_Face& aF1x,
451                                                       const TopoDS_Face& aF2y,
452 #if OCC_VERSION_LARGE > 0x06050200
453                                                       const Handle(IntTools_Context)& aCtx)
454 #else
455                                                       IntTools_Context& aCtx)
456 #endif
457 {
458   Standard_Boolean bFlag;
459   // Modified  Thu Sep 14 14:35:18 2006
460   // Contribution of Samtech www.samcef.com BEGIN
461   Standard_Integer aNbE1, aNbE2;
462   Standard_Real aTolF1, aTolF2, aTol;
463   gp_Pnt2d aP2D;
464   gp_Pnt aP;
465   TopoDS_Face aF1, aF2;
466   TopExp_Explorer aExp;
467   TopTools_MapOfShape aME1, aME2;
468   TopTools_MapIteratorOfMapOfShape aIt;
469   //
470   bFlag=Standard_False;
471   // Contribution of Samtech www.samcef.com END
472   //
473   aF1=aF1x;
474   aF1.Orientation(TopAbs_FORWARD);
475   aF2=aF2y;
476   aF2.Orientation(TopAbs_FORWARD);
477   //
478   // Modified  Thu Sep 14 14:35:18 2006
479   // Contribution of Samtech www.samcef.com BEGIN
480   //
481   // 1
482   aExp.Init(aF1, TopAbs_EDGE);
483   for (; aExp.More(); aExp.Next()) {
484     const TopoDS_Edge& aE=TopoDS::Edge(aExp.Current());
485     if (!BRep_Tool::Degenerated(aE)) {
486       aME1.Add(aE);
487     }
488   }
489   //
490   aExp.Init(aF2, TopAbs_EDGE);
491   for (; aExp.More(); aExp.Next()) {
492     const TopoDS_Edge& aE=TopoDS::Edge(aExp.Current());
493     if (!BRep_Tool::Degenerated(aE)) {
494       if (!aME1.Contains(aE)) {
495         return bFlag;
496       }
497       aME2.Add(aE);
498     }
499   }
500   //
501   // Contribution of Samtech www.samcef.com END
502   //
503   aNbE1=aME1.Extent();
504   aNbE2=aME2.Extent();
505   //
506   if(!aNbE1 || !aNbE2){
507     return bFlag;
508   }
509   //
510   if(aNbE1!=aNbE2) {
511     return bFlag;
512   }
513   //
514   // 2
515   aTolF1=BRep_Tool::Tolerance(aF1);
516   aTolF2=BRep_Tool::Tolerance(aF2);
517   aTol=aTolF1+aTolF2;
518   //
519   aIt.Initialize(aME1);
520   for (; aIt.More(); aIt.Next()) {
521     const TopoDS_Edge& aE=TopoDS::Edge(aIt.Key());
522     BOPTools_Tools3D::PointNearEdge(aE, aF1, aP2D, aP);
523 #if OCC_VERSION_LARGE > 0x06050200
524     bFlag=aCtx->IsValidPointForFace(aP, aF2, aTol);
525 #else
526     bFlag=aCtx.IsValidPointForFace(aP, aF2, aTol);
527 #endif
528     break;
529   }
530   //
531   return bFlag;
532 }
533 //=======================================================================
534 // function: FindChains
535 // purpose :
536 //=======================================================================
537   void NMTTools_Tools::FindChains(const NMTTools_ListOfCoupleOfShape& aLCS,
538                                   NMTTools_IndexedDataMapOfShapeIndexedMapOfShape& aMapChains)
539 {
540   NMTTools_ListIteratorOfListOfCoupleOfShape aItCS;
541   NMTTools_IndexedDataMapOfShapeIndexedMapOfShape aMCV;
542   //
543   aItCS.Initialize(aLCS);
544   for (; aItCS.More(); aItCS.Next()) {
545     const NMTTools_CoupleOfShape& aCS=aItCS.Value();
546     //
547     const TopoDS_Shape& aF1=aCS.Shape1();
548     const TopoDS_Shape& aF2=aCS.Shape2();
549     //
550     //
551     if (aMCV.Contains(aF1)) {
552       TopTools_IndexedMapOfShape& aMV=aMCV.ChangeFromKey(aF1);
553       aMV.Add(aF1);
554       aMV.Add(aF2);
555     }
556     else {
557       TopTools_IndexedMapOfShape aMV;
558       aMV.Add(aF1);
559       aMV.Add(aF2);
560       aMCV.Add(aF1, aMV);
561     }
562     //
563     if (aMCV.Contains(aF2)) {
564       TopTools_IndexedMapOfShape& aMV=aMCV.ChangeFromKey(aF2);
565       aMV.Add(aF1);
566       aMV.Add(aF2);
567     }
568     else {
569       TopTools_IndexedMapOfShape aMV;
570       aMV.Add(aF1);
571       aMV.Add(aF2);
572       aMCV.Add(aF2, aMV);
573     }
574   }
575   NMTTools_Tools::FindChains(aMCV, aMapChains);
576 }
577 //=======================================================================
578 // function: FindChains
579 // purpose :
580 //=======================================================================
581   void NMTTools_Tools::FindChains(const NMTTools_IndexedDataMapOfShapeIndexedMapOfShape& aMCV,
582                                   NMTTools_IndexedDataMapOfShapeIndexedMapOfShape& aMapChains)
583 {
584   Standard_Integer  i, j, aNbCV, aNbV;
585   TopTools_IndexedMapOfShape aProcessed, aChain;
586   //
587   aNbCV=aMCV.Extent();
588   for (i=1; i<=aNbCV; ++i) {
589     const TopoDS_Shape& aF=aMCV.FindKey(i);
590     if (aProcessed.Contains(aF)) {
591       continue;
592     }
593     //
594     aProcessed.Add(aF);
595     aChain.Add(aF);
596     //
597     const TopTools_IndexedMapOfShape& aMV=aMCV(i);
598     aNbV=aMV.Extent();
599     for (j=1; j<=aNbV; ++j) {
600       const TopoDS_Shape& aFx=aMV(j);
601       ProcessBlock(aFx, aMCV, aProcessed, aChain);
602     }
603     aMapChains.Add(aF, aChain);
604     aChain.Clear();
605   }
606 }
607 //=======================================================================
608 // function: ProcessBlock
609 // purpose:
610 //=======================================================================
611 void ProcessBlock(const TopoDS_Shape& aF,
612                   const NMTTools_IndexedDataMapOfShapeIndexedMapOfShape& aMCV,
613                   TopTools_IndexedMapOfShape& aProcessed,
614                   TopTools_IndexedMapOfShape& aChain)
615 {
616   Standard_Integer j, aNbV;
617   //
618   if (aProcessed.Contains(aF)) {
619     return;
620   }
621   aProcessed.Add(aF);
622   aChain.Add(aF);
623   //
624   const TopTools_IndexedMapOfShape& aMV=aMCV.FindFromKey(aF);
625   aNbV=aMV.Extent();
626   for (j=1; j<=aNbV; ++j) {
627     const TopoDS_Shape& aFx=aMV(j);
628     ProcessBlock(aFx, aMCV, aProcessed, aChain);
629   }
630 }