Salome HOME
Merge remote branch 'origin/V7_dev' into V8_0_0_BR
[modules/geom.git] / src / GEOMImpl / GEOMImpl_Block6Explorer.cxx
1 // Copyright (C) 2007-2015  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, or (at your option) any later version.
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
23 #include <Standard_Stream.hxx>
24
25 #include <GEOMImpl_Block6Explorer.hxx>
26
27 #include <ShHealOper_ShapeProcess.hxx>
28
29 #include "utilities.h"
30
31 #include <Basics_OCCTVersion.hxx>
32
33 #include <BRep_Tool.hxx>
34 #include <BRep_TFace.hxx>
35 #include <BRep_Builder.hxx>
36 #include <BRepLib.hxx>
37 #include <BRepLib_FindSurface.hxx>
38 #include <BRepTools.hxx>
39 #include <BRepTools_WireExplorer.hxx>
40 #include <BRepOffsetAPI_ThruSections.hxx>
41 #include <BRepOffsetAPI_MakeFilling.hxx>
42 #include <BRepCheck_Analyzer.hxx>
43 #include <BRepBuilderAPI_Copy.hxx>
44 #include <BRepBuilderAPI_MakeEdge.hxx>
45 #include <BRepBuilderAPI_MakeWire.hxx>
46 #include <BRepBuilderAPI_MakeFace.hxx>
47 #include <BRepBuilderAPI_Transform.hxx>
48
49 #include <TopAbs.hxx>
50 #include <TopoDS.hxx>
51 #include <TopoDS_Shape.hxx>
52 #include <TopoDS_Edge.hxx>
53 #include <TopoDS_Wire.hxx>
54 #include <TopoDS_Solid.hxx>
55 #include <TopExp.hxx>
56 #include <TopExp_Explorer.hxx>
57 #include <TopTools_MapOfShape.hxx>
58 #include <TopTools_ListOfShape.hxx>
59 #include <TopTools_ListIteratorOfListOfShape.hxx>
60 #include <TopTools_IndexedMapOfShape.hxx>
61 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
62
63 #include <Geom_Curve.hxx>
64 #include <Geom_TrimmedCurve.hxx>
65 #include <GeomFill_Generator.hxx>
66
67 #include <gce_MakePln.hxx>
68
69 #include <Precision.hxx>
70 #include <gp_Pnt.hxx>
71 #include <gp_Pln.hxx>
72 #include <TColgp_Array1OfPnt.hxx>
73
74 #include <StdFail_NotDone.hxx>
75 #include <Standard_NullObject.hxx>
76 #include <Standard_TypeMismatch.hxx>
77 #include <Standard_ConstructionError.hxx>
78 #include <Standard_NoSuchObject.hxx>
79
80 #define NBFACES 6
81 #define NBEDGES 12
82 #define NBVERTS 8
83
84 #define PLANAR_FACE_MAX_TOLERANCE 1e-06
85
86 // The following macro, when enabled, causes pcurves upgrade after MakeFilling algorithm
87 // in MakeAnyFace function;
88 // WARNING: it may lead to extra vertices generation by partition algorithm
89 // in some cases, for example when fillet is made on a PipeTShape - 
90 // see issues 0021568 and 0021550
91 // VSR (15/05/2012): macro commented out (disabled) to avoid extra vertices!
92 //#define MAKE_FACE_UPGRADE_PCURVES
93
94 // The following macro, when enabled, causes fixing tolerance for pcurves
95 // after BRepBuilderAPI_MakeFace + ShHealOper_ShapeProcess in MakeAnyFace function;
96 // This sometimes allows to fix problems of extra vertices generation
97 // see issue 0022706
98 // VSR (17/11/2014): macro enabled
99 #define MAKE_FACE_PCURVES_FIX_TOLERANCE
100
101 #ifdef MAKE_FACE_PCURVES_FIX_TOLERANCE
102 #include <BOPTools_AlgoTools.hxx>
103 #include <NCollection_DataMap.hxx>
104 #include <ShapeFix_ShapeTolerance.hxx>
105 #endif
106
107 static Standard_Integer mod4 (Standard_Integer nb)
108 {
109   if (nb <= 0) return nb + 4;
110   if (nb > 4)  return nb - 4;
111   return nb;
112 }
113
114 static Standard_Integer edge_id (const Standard_Integer theFaceID,
115                                  const Standard_Integer theEdgeNB)
116 {
117   static Standard_Integer edge_ids[NBFACES][4] = {
118     {  1,  2,  3,  4 },   // face 1
119     {  5,  6,  7,  8 },   // face 2
120     {  9,  5, 10,  1 },   // face 3
121     { 12,  7, 11,  3 },   // face 4
122     {  4, 12,  8,  9 },   // face 5
123     {  2, 11,  6, 10 } }; // face 6
124
125   return edge_ids[theFaceID - 1][theEdgeNB - 1];
126 }
127
128 static Standard_Integer side_edge_id (const Standard_Integer theEdgeNB)
129 {
130   static Standard_Integer side_edge_ids[4] = {9, 10, 11, 12};
131
132   return side_edge_ids[theEdgeNB - 1];
133 }
134
135 static Standard_Integer vertex_id (const Standard_Integer theFaceID,
136                                    const Standard_Integer theVertexNB)
137 {
138   static Standard_Integer vertex_ids[NBFACES][4] = {
139     { 1, 2, 3, 4 },   // face 1
140     { 5, 6, 7, 8 },   // face 2
141     { 1, 5, 6, 2 },   // face 3
142     { 4, 8, 7, 3 },   // face 4
143     { 1, 4, 8, 5 },   // face 5
144     { 2, 3, 7, 6 } }; // face 6
145
146   return vertex_ids[theFaceID - 1][theVertexNB - 1];
147 }
148
149 static Standard_Integer vertex_id_edge (const Standard_Integer theEdgeID, // [1,12]
150                                         const Standard_Integer theVertexNB) // [1,2]
151 {
152   static Standard_Integer vertex_ids_edge[NBEDGES][2] = {
153     {1, 2},   // edge 1
154     {2, 3},   // edge 2
155     {3, 4},   // edge 3
156     {4, 1},   // edge 4
157     {5, 6},   // edge 5
158     {6, 7},   // edge 6
159     {7, 8},   // edge 7
160     {8, 5},   // edge 8
161     {1, 5},   // edge 9
162     {2, 6},   // edge 10
163     {3, 7},   // edge 11
164     {4, 8} }; // edge 12
165
166   return vertex_ids_edge[theEdgeID - 1][theVertexNB - 1];
167 }
168
169 static Standard_Integer face_id_edges (const Standard_Integer theEdge1ID, // [1,12]
170                                        const Standard_Integer theEdge2ID) // [1,12]
171 {
172   static Standard_Integer face_ids_edges[NBEDGES][NBEDGES] = {
173     // 1  2  3  4  5  6  7  8  9  10 11 12
174     {  0, 1, 1, 1, 3, 0, 0, 0, 3, 3, 0, 0  },   // edge 1
175     {  1, 0, 1, 1, 0, 6, 0, 0, 0, 6, 6, 0  },   // edge 2
176     {  1, 1, 0, 1, 0, 0, 4, 0, 0, 0, 4, 4  },   // edge 3
177     {  1, 1, 1, 0, 0, 0, 0, 5, 5, 0, 0, 5  },   // edge 4
178     {  3, 0, 0, 0, 0, 2, 2, 2, 3, 3, 0, 0  },   // edge 5
179     {  0, 6, 0, 0, 2, 0, 2, 2, 0, 6, 6, 0  },   // edge 6
180     {  0, 0, 4, 0, 2, 2, 0, 2, 0, 0, 4, 4  },   // edge 7
181     {  0, 0, 0, 5, 2, 2, 2, 0, 5, 0, 0, 5  },   // edge 8
182     {  3, 0, 0, 5, 3, 0, 0, 5, 0, 3, 0, 5  },   // edge 9
183     {  3, 6, 0, 0, 3, 6, 0, 0, 3, 0, 6, 0  },   // edge 10
184     {  0, 6, 4, 0, 0, 6, 4, 0, 0, 6, 0, 4  },   // edge 11
185     {  0, 0, 4, 5, 0, 0, 4, 5, 5, 0, 4, 0  } }; // edge 12
186
187   return face_ids_edges[theEdge1ID - 1][theEdge2ID - 1];
188 }
189
190 static Standard_Integer edge_id_vertices (const Standard_Integer theVertex1ID, // [1,8]
191                                           const Standard_Integer theVertex2ID) // [1,8]
192 {
193   static Standard_Integer edge_ids_vertices[NBVERTS][NBVERTS] = {
194     // 1   2   3   4   5   6   7   8
195     {  0,  1,  0,  4,  9,  0,  0,  0},   // vertex 1
196     {  1,  0,  2,  0,  0, 10,  0,  0},   // vertex 2
197     {  0,  2,  0,  3,  0,  0, 11,  0},   // vertex 3
198     {  4,  0,  3,  0,  0,  0,  0, 12},   // vertex 4
199     {  9,  0,  0,  0,  0,  5,  0,  8},   // vertex 5
200     {  0, 10,  0,  0,  5,  0,  6,  0},   // vertex 6
201     {  0,  0, 11,  0,  0,  6,  0,  7},   // vertex 7
202     {  0,  0,  0, 12,  8,  0,  7,  0} }; // vertex 8
203
204   return edge_ids_vertices[theVertex1ID - 1][theVertex2ID - 1];
205 }
206
207 static Standard_Integer edge_id_faces (const Standard_Integer theFace1ID, // [1,6]
208                                        const Standard_Integer theFace2ID) // [1,6]
209 {
210   static Standard_Integer edge_ids_faces[NBFACES][NBFACES] = {
211     // 1   2   3   4   5   6
212     {  0,  0,  1,  3,  4,  2  },   // face 1
213     {  0,  0,  5,  7,  8,  6  },   // face 2
214     {  1,  5,  0,  0,  9, 10  },   // face 3
215     {  3,  7,  0,  0, 12, 11  },   // face 4
216     {  4,  8,  9, 12,  0,  0  },   // face 5
217     {  2,  6, 10, 11,  0,  0  } }; // face 6
218
219   return edge_ids_faces[theFace1ID - 1][theFace2ID - 1];
220 }
221
222 //=======================================================================
223 //function : GEOMImpl_Block6Explorer
224 //purpose  : Constructor
225 //=======================================================================
226 GEOMImpl_Block6Explorer::GEOMImpl_Block6Explorer ()
227      : myFaces(1,NBFACES), myEdges(1,NBEDGES), myVertices(1,NBVERTS)
228 {
229 }
230
231 //=======================================================================
232 //function : GetVertex
233 //purpose  :
234 //=======================================================================
235 TopoDS_Shape GEOMImpl_Block6Explorer::GetVertex (const Standard_Integer theVertexID)
236 {
237   TopoDS_Shape aNullShape;
238   if (theVertexID < 1 || theVertexID > NBVERTS) return aNullShape;
239   return myVertices(theVertexID);
240 }
241
242 //=======================================================================
243 //function : GetVertexID
244 //purpose  :
245 //=======================================================================
246 Standard_Integer GEOMImpl_Block6Explorer::GetVertexID (const TopoDS_Shape& theVertex)
247 {
248   for (Standard_Integer id = 1; id <= NBVERTS; id++) {
249     if (theVertex.IsSame(myVertices(id))) return id;
250   }
251   Standard_NoSuchObject::Raise("The Vertex does not belong to the Block");
252   return 0;
253 }
254
255 //=======================================================================
256 //function : GetVertexID
257 //purpose  :
258 //=======================================================================
259 Standard_Integer GEOMImpl_Block6Explorer::GetVertexID (const Standard_Integer theFaceID,
260                                                        const Standard_Integer theVertexNB)
261 {
262   return vertex_id(theFaceID, theVertexNB);
263 }
264
265 //=======================================================================
266 //function : GetVertexOnEdgeID
267 //purpose  :
268 //=======================================================================
269 Standard_Integer GEOMImpl_Block6Explorer::GetVertexOnEdgeID
270                                      (const Standard_Integer theEdgeID,
271                                       const Standard_Integer theVertexNB)
272 {
273   return vertex_id_edge(theEdgeID, theVertexNB);
274 }
275
276 //=======================================================================
277 //function : GetEdge
278 //purpose  :
279 //=======================================================================
280 TopoDS_Shape GEOMImpl_Block6Explorer::GetEdge (const Standard_Integer theEdgeID,
281                                                const Standard_Boolean doMake)
282 {
283   TopoDS_Shape aNullShape;
284   if (theEdgeID < 1 || theEdgeID > NBEDGES) return aNullShape;
285   if (myEdges(theEdgeID).IsNull() && doMake) {
286     // Create the required edge as a linear segment between
287     // corresponding vertices and put it in the Block's edges
288     BRepBuilderAPI_MakeEdge ME (TopoDS::Vertex(myVertices(vertex_id_edge(theEdgeID, 1))),
289                                 TopoDS::Vertex(myVertices(vertex_id_edge(theEdgeID, 2))));
290     if (!ME.IsDone()) {
291       Standard_ConstructionError::Raise("Edge construction failed");
292     }
293     myEdges(theEdgeID) = ME.Shape();
294   }
295
296   return myEdges(theEdgeID);
297 }
298
299 //=======================================================================
300 //function : GetEdgeID
301 //purpose  :
302 //=======================================================================
303 Standard_Integer GEOMImpl_Block6Explorer::GetEdgeID (const TopoDS_Shape& theEdge)
304 {
305   for (Standard_Integer id = 1; id <= NBEDGES; id++) {
306     if (theEdge.IsSame(myEdges(id))) return id;
307   }
308   Standard_NoSuchObject::Raise("The Edge does not belong to the Block");
309   return 0;
310 }
311
312 //=======================================================================
313 //function : GetEdgeID
314 //purpose  :
315 //=======================================================================
316 Standard_Integer GEOMImpl_Block6Explorer::GetEdgeID (const Standard_Integer theFaceID,
317                                                      const Standard_Integer theEdgeNB)
318 {
319   return edge_id(theFaceID, theEdgeNB);
320 }
321
322 //=======================================================================
323 //function : FindEdgeID
324 //purpose  :
325 //=======================================================================
326 Standard_Integer GEOMImpl_Block6Explorer::FindEdgeID (const Standard_Integer theVertex1ID,
327                                                       const Standard_Integer theVertex2ID)
328 {
329   return edge_id_vertices(theVertex1ID, theVertex2ID);
330 }
331
332 //=======================================================================
333 //function : FindCommonEdgeID
334 //purpose  :
335 //=======================================================================
336 Standard_Integer GEOMImpl_Block6Explorer::FindCommonEdgeID
337                                       (const Standard_Integer theFace1ID,
338                                        const Standard_Integer theFace2ID)
339 {
340   return edge_id_faces(theFace1ID, theFace2ID);
341 }
342
343 //=======================================================================
344 //function : GetFace
345 //purpose  :
346 //=======================================================================
347 TopoDS_Shape GEOMImpl_Block6Explorer::GetFace (const Standard_Integer theFaceID,
348                                                const Standard_Boolean doMake)
349 {
350   TopoDS_Shape aNullShape;
351   if (theFaceID < 1 || theFaceID > NBFACES) return aNullShape;
352
353   if (myFaces(theFaceID).IsNull() && doMake) {
354
355     // Create the required face between
356     // corresponding edges and put it in the Block's faces
357
358     TopoDS_Shape E1 = GetEdge(edge_id(theFaceID, 1), doMake);
359     TopoDS_Shape E2 = GetEdge(edge_id(theFaceID, 2), doMake);
360     TopoDS_Shape E3 = GetEdge(edge_id(theFaceID, 3), doMake);
361     TopoDS_Shape E4 = GetEdge(edge_id(theFaceID, 4), doMake);
362
363     BRepBuilderAPI_MakeWire MW (TopoDS::Edge(E1),
364                                 TopoDS::Edge(E2),
365                                 TopoDS::Edge(E3),
366                                 TopoDS::Edge(E4));
367     if (!MW.IsDone()) {
368       Standard_ConstructionError::Raise("Wire construction failed");
369     }
370     TopoDS_Shape aFace;
371     MakeFace(MW, Standard_False, aFace);
372     if (aFace.IsNull()) {
373       Standard_ConstructionError::Raise("Face construction failed");
374     }
375     myFaces(theFaceID) = aFace;
376   }
377
378   return myFaces(theFaceID);
379 }
380
381 //=======================================================================
382 //function : GetFaceID
383 //purpose  :
384 //=======================================================================
385 Standard_Integer GEOMImpl_Block6Explorer::GetFaceID (const TopoDS_Shape& theFace)
386 {
387   for (Standard_Integer id = 1; id <= NBFACES; id++) {
388     if (theFace.IsSame(myFaces(id))) return id;
389   }
390   Standard_NoSuchObject::Raise("The Face does not belong to the Block");
391   return 0;
392 }
393
394 //=======================================================================
395 //function : FindFaceID
396 //purpose  :
397 //=======================================================================
398 Standard_Integer GEOMImpl_Block6Explorer::FindFaceID (const Standard_Integer theEdge1ID,
399                                                       const Standard_Integer theEdge2ID)
400 {
401   return face_id_edges(theEdge1ID, theEdge2ID);
402 }
403
404 //=======================================================================
405 //function : GetOppositeFaceID
406 //purpose  :
407 //=======================================================================
408 Standard_Integer GEOMImpl_Block6Explorer::GetOppositeFaceID (const Standard_Integer theFaceID)
409 {
410   Standard_Integer opp_face_id[NBFACES + 1] = {
411     0,
412     2,  // to 1 face
413     1,  // to 2 face
414     4,  // to 3 face
415     3,  // to 4 face
416     6,  // to 5 face
417     5}; // to 6 face
418
419   return opp_face_id[theFaceID];
420 }
421
422 //=======================================================================
423 //function : IsSimilarFaces
424 //purpose  :
425 //=======================================================================
426 Standard_Boolean GEOMImpl_Block6Explorer::IsSimilarFaces (const Standard_Integer theFace1ID,
427                                                           const Standard_Integer theFace2ID,
428                                                           const gp_Trsf          theTransformation)
429 {
430   Standard_Integer common_edge_id = FindCommonEdgeID(theFace1ID, theFace2ID);
431
432   if (common_edge_id == 0) { // opposite faces
433     for (Standard_Integer id = 1; id <= 4; id++) {
434       TopoDS_Shape E1 = GetEdge(edge_id(theFace1ID, id));
435       TopoDS_Shape E2 = GetEdge(edge_id(theFace2ID, id));
436
437       BRepBuilderAPI_Transform aTrsf (E1, theTransformation, Standard_False);
438       if (!IsSimilarEdges(aTrsf.Shape(), E2))
439         return Standard_False;
440     }
441   } else { // the faces have common edge
442     TopTools_Array1OfShape aVerts1 (1,4);
443     TopTools_Array1OfShape aVerts2 (1,4);
444
445     Standard_Integer common_vertex1 = GetVertexOnEdgeID(common_edge_id, 1);
446     Standard_Integer common_vertex2 = GetVertexOnEdgeID(common_edge_id, 2);
447     aVerts1(1) = myVertices(common_vertex1);
448     aVerts1(2) = myVertices(common_vertex2);
449     aVerts2(1) = myVertices(common_vertex1);
450     aVerts2(2) = myVertices(common_vertex2);
451
452     Standard_Integer not_common_v11 = 0, not_common_v12 = 0;
453     Standard_Integer vnb, vid;
454     for (vnb = 1; vnb <= 4; vnb++) {
455       vid = GetVertexID(theFace1ID, vnb);
456       if (vid != common_vertex1 && FindEdgeID(vid, common_vertex1) == 0) {
457         not_common_v12 = vid;
458       } else {
459         if (vid != common_vertex2 && FindEdgeID(vid, common_vertex2) == 0) {
460           not_common_v11 = vid;
461         }
462       }
463     }
464
465     Standard_Integer not_common_v21 = 0, not_common_v22 = 0;
466     for (vnb = 1; vnb <= 4; vnb++) {
467       vid = GetVertexID(theFace2ID, vnb);
468       if (vid != common_vertex1 && FindEdgeID(vid, common_vertex1) == 0) {
469         not_common_v22 = vid;
470       } else {
471         if (vid != common_vertex2 && FindEdgeID(vid, common_vertex2) == 0) {
472           not_common_v21 = vid;
473         }
474       }
475     }
476     aVerts1(3) = myVertices(not_common_v11);
477     aVerts1(4) = myVertices(not_common_v12);
478     aVerts2(3) = myVertices(not_common_v21);
479     aVerts2(4) = myVertices(not_common_v22);
480
481     for (Standard_Integer id = 1; id <= 4; id++) {
482       BRepBuilderAPI_Transform aTrsf (aVerts1(id), theTransformation, Standard_False);
483       TopoDS_Vertex V1 = TopoDS::Vertex(aTrsf.Shape());
484       TopoDS_Vertex V2 = TopoDS::Vertex(aVerts2(id));
485       if (!BRepTools::Compare(V1, V2)) {
486         return Standard_False;
487       }
488     }
489   }
490
491   return Standard_True;
492 }
493
494 //============ Initialization methods ===================================
495
496 //=======================================================================
497 //function : InitByBlock
498 //purpose  :
499 //=======================================================================
500 void GEOMImpl_Block6Explorer::InitByBlock (const TopoDS_Shape& theBlock)
501 {
502   // 1. Find any one face of the block
503   TopExp_Explorer faces (theBlock, TopAbs_FACE);
504   if (!faces.More()) {
505     Standard_ConstructionError::Raise("The block has no faces");
506   }
507   TopoDS_Shape aFirstFace = faces.Current();
508
509   // 2. Store all elements of the block relatively aFirstFace
510   InitByBlockAndFace(theBlock, aFirstFace);
511 }
512
513 //=======================================================================
514 //function : InitByBlockAndFace
515 //purpose  :
516 //=======================================================================
517 void GEOMImpl_Block6Explorer::InitByBlockAndFace (const TopoDS_Shape& theBlock,
518                                                   const TopoDS_Shape& theFace)
519 {
520   myFaces(1) = theFace;
521
522   // 2. Get wire of the first face
523   TopExp_Explorer wires (myFaces(1), TopAbs_WIRE);
524   if (!wires.More()) {
525     Standard_ConstructionError::Raise("A face of the block has no wires");
526   }
527   TopoDS_Shape aWire = wires.Current();
528   wires.Next();
529   if (wires.More()) {
530     Standard_ConstructionError::Raise("A face of the block has more than one wires");
531   }
532
533   // 3. Explore wire to init edges and vertices of the first face
534   BRepTools_WireExplorer aWE (TopoDS::Wire(aWire), TopoDS::Face(myFaces(1)));
535   Standard_Integer nb = 1;
536   for (; aWE.More(); aWE.Next(), nb++) {
537     if (nb > 4) {
538       Standard_ConstructionError::Raise("A face of the block has more than four edges");
539     }
540     myEdges(edge_id(1, nb)) = aWE.Current();
541     myVertices(vertex_id(1, nb)) = aWE.CurrentVertex();
542   }
543   if (nb < 5) {
544     Standard_ConstructionError::Raise("A face of the block has less than four edges");
545   }
546
547   // 2. Store all other elements of the block
548   InitByBlockAndVertices (theBlock,
549                           myVertices(vertex_id(1,1)),
550                           myVertices(vertex_id(1,2)),
551                           myVertices(vertex_id(1,3)));
552 }
553
554 //=======================================================================
555 //function : InitByBlockAndEdges
556 //purpose  :
557 //=======================================================================
558 void GEOMImpl_Block6Explorer::InitByBlockAndEdges (const TopoDS_Shape& theBlock,
559                                                    const TopoDS_Shape& theEdge1,
560                                                    const TopoDS_Shape& theEdge3)
561 {
562   // 1. Store vertices and edges of the first face
563
564   // 1.1. Store two given edges
565   myEdges(edge_id(1, 1)) = theEdge1;
566   myEdges(edge_id(1, 3)) = theEdge3;
567
568   // 1.2. Find and store the first face
569   TopTools_IndexedDataMapOfShapeListOfShape MEF;
570   MapShapesAndAncestors(theBlock, TopAbs_EDGE, TopAbs_FACE, MEF);
571   if (MEF.Extent() != NBEDGES) {
572     Standard_TypeMismatch::Raise("Block has wrong number of edges");
573   }
574   const TopTools_ListOfShape& aFacesOfE1 = MEF.FindFromKey(theEdge1);
575   const TopTools_ListOfShape& aFacesOfE3 = MEF.FindFromKey(theEdge3);
576
577   Standard_Boolean isFound = Standard_False;
578   TopTools_ListIteratorOfListOfShape anIterF1 (aFacesOfE1);
579   for (; anIterF1.More() && !isFound; anIterF1.Next()) {
580
581     TopTools_ListIteratorOfListOfShape anIterF3 (aFacesOfE3);
582     for (; anIterF3.More() && !isFound; anIterF3.Next()) {
583
584       if (anIterF1.Value().IsSame(anIterF3.Value())) {
585         isFound = Standard_True;
586
587         // Store the face, defined by two opposite edges
588         myFaces(1) = anIterF1.Value();
589       }
590     }
591   }
592   if (!isFound) {
593     Standard_ConstructionError::Raise
594       ("Edges 1 and 2 do not belong to one face of the block");
595   }
596
597   // 1.3. Make vertices of the first edge the first and the
598   //      second vertices of the first face. Order is free.
599   TopoDS_Edge E = TopoDS::Edge(theEdge1);
600   TopoDS_Vertex V1, V2;
601   TopExp::Vertices(E, V1, V2, Standard_True);
602   myVertices(vertex_id(1,1)) = V1;
603   myVertices(vertex_id(1,2)) = V2;
604
605   // Init maps vertex->list_of_edges for the face
606   TopTools_IndexedDataMapOfShapeListOfShape M1;
607   MapShapesAndAncestors(myFaces(1), TopAbs_VERTEX, TopAbs_EDGE, M1);
608   if (M1.Extent() != 4) {
609     Standard_TypeMismatch::Raise("The first face of block has wrong number of vertices");
610   }
611
612   // 1.4. Find and store others elements of the first face
613
614   // edges of the first vertex
615   TopoDS_Shape E1_f = M1.FindFromKey(V1).First();
616   TopoDS_Shape E1_l = M1.FindFromKey(V1).Last();
617
618   if (E1_f.IsSame(theEdge1)) {
619     myEdges(edge_id(1, 4)) = E1_l;
620   } else {
621     myEdges(edge_id(1, 4)) = E1_f;
622   }
623
624   // fourth vertex
625   TopoDS_Edge E4 = TopoDS::Edge(myEdges(edge_id(1, 4)));
626   TopoDS_Vertex V41, V42;
627   TopExp::Vertices(E4, V41, V42, Standard_True);
628   if (V41.IsSame(V1)) {
629     myVertices(vertex_id(1,4)) = V42;
630   } else {
631     myVertices(vertex_id(1,4)) = V41;
632   }
633
634   // edges of the second vertex
635   TopoDS_Shape E2_f = M1.FindFromKey(V2).First();
636   TopoDS_Shape E2_l = M1.FindFromKey(V2).Last();
637
638   if (E2_f.IsSame(theEdge1)) {
639     myEdges(edge_id(1, 2)) = E2_l;
640   } else {
641     myEdges(edge_id(1, 2)) = E2_f;
642   }
643
644   // fird vertex
645   TopoDS_Edge E2 = TopoDS::Edge(myEdges(edge_id(1, 2)));
646   TopoDS_Vertex V21, V22;
647   TopExp::Vertices(E2, V21, V22, Standard_True);
648   if (V21.IsSame(V2)) {
649     myVertices(vertex_id(1,3)) = V22;
650   } else {
651     myVertices(vertex_id(1,3)) = V21;
652   }
653
654   // 2. Store all other elements of the block
655   InitByBlockAndVertices (theBlock,
656                           myVertices(vertex_id(1,1)),
657                           myVertices(vertex_id(1,2)),
658                           myVertices(vertex_id(1,3)));
659 }
660
661 //=======================================================================
662 //function : InitByBlockAndVertices
663 //purpose  :
664 //=======================================================================
665 void GEOMImpl_Block6Explorer::InitByBlockAndVertices (const TopoDS_Shape& theBlock,
666                                                       const TopoDS_Shape& theVertex1,
667                                                       const TopoDS_Shape& theVertex2,
668                                                       const TopoDS_Shape& theVertex3)
669 {
670   // Here we suppose, that vertices are ordered, i.e. exists edge between
671   // theVertex1 and theVertex2 and edge between theVertex2 and theVertex3
672
673   // 1. Store vertices and edges of the first face.
674   //    If the first face is initialized, it means, that this
675   //    method is called from another initialization method, and all
676   //    vertices and edges of the first face are also initialized
677   if (myFaces(1).IsNull()) {
678
679     // 1.1. Store first three vertices
680     myVertices(vertex_id(1, 1)) = theVertex1;
681     myVertices(vertex_id(1, 2)) = theVertex2;
682     myVertices(vertex_id(1, 3)) = theVertex3;
683
684     // 1.2. Find and store the first face
685     TopTools_IndexedDataMapOfShapeListOfShape MVF;
686     MapShapesAndAncestors(theBlock, TopAbs_VERTEX, TopAbs_FACE, MVF);
687     if (MVF.Extent() != NBVERTS) {
688       Standard_TypeMismatch::Raise("Block has wrong number of vertices");
689     }
690     const TopTools_ListOfShape& aFacesOfV1 = MVF.FindFromKey(theVertex1);
691     const TopTools_ListOfShape& aFacesOfV3 = MVF.FindFromKey(theVertex3);
692
693     Standard_Boolean isFound = Standard_False;
694     TopTools_ListIteratorOfListOfShape anIterF1 (aFacesOfV1);
695     for (; anIterF1.More() && !isFound; anIterF1.Next()) {
696
697       TopTools_ListIteratorOfListOfShape anIterF3 (aFacesOfV3);
698       for (; anIterF3.More() && !isFound; anIterF3.Next()) {
699
700         if (anIterF1.Value().IsSame(anIterF3.Value())) {
701           isFound = Standard_True;
702
703           // Store the face, defined by two opposite vertices
704           myFaces(1) = anIterF1.Value();
705         }
706       }
707     }
708     if (!isFound) {
709       Standard_ConstructionError::Raise
710         ("Vertices 1 and 3 do not belong to one face of the block");
711     }
712
713     // Init maps vertex->list_of_edges for the face
714     TopTools_IndexedDataMapOfShapeListOfShape M1;
715     MapShapesAndAncestors(myFaces(1), TopAbs_VERTEX, TopAbs_EDGE, M1);
716     if (M1.Extent() != 4) {
717       Standard_TypeMismatch::Raise("The first face of block has wrong number of vertices");
718     }
719
720     // 1.3. Find and store edges and last vertex of the first face
721     const TopTools_ListOfShape& anEdgesOfV1 = M1.FindFromKey(theVertex1);
722     const TopTools_ListOfShape& anEdgesOfV2 = M1.FindFromKey(theVertex2);
723     const TopTools_ListOfShape& anEdgesOfV3 = M1.FindFromKey(theVertex3);
724
725     TopTools_ListIteratorOfListOfShape anIterE2 (anEdgesOfV2);
726     for (; anIterE2.More(); anIterE2.Next()) {
727
728       TopTools_ListIteratorOfListOfShape anIterE1 (anEdgesOfV1);
729       for (; anIterE1.More(); anIterE1.Next()) {
730
731         if (anIterE1.Value().IsSame(anIterE2.Value())) {
732           // Store the first edge, defined by two vertices
733           myEdges(edge_id(1,1)) = anIterE1.Value();
734
735         } else {
736           // Store the last edge
737           myEdges(edge_id(1,4)) = anIterE1.Value();
738
739           // Find and store the last vertex
740           TopoDS_Edge E = TopoDS::Edge(myEdges(4));
741           TopoDS_Vertex V1, V2;
742           TopExp::Vertices(E, V1, V2, Standard_True);
743
744           if (V1.IsSame(theVertex1)) {
745             myVertices(vertex_id(1,4)) = V2;
746           } else {
747             myVertices(vertex_id(1,4)) = V1;
748           }
749         }
750       }
751
752       TopTools_ListIteratorOfListOfShape anIterE3 (anEdgesOfV3);
753       for (; anIterE3.More(); anIterE3.Next()) {
754
755         if (anIterE3.Value().IsSame(anIterE2.Value())) {
756           // Store the second edge, defined by two vertices
757           myEdges(edge_id(1,2)) = anIterE3.Value();
758
759         } else {
760           // Store the fird edge
761           myEdges(edge_id(1,3)) = anIterE3.Value();
762         }
763       }
764     }
765   }
766
767   // Init map vertex->list_of_edges for the block
768   TopTools_IndexedDataMapOfShapeListOfShape MB;
769   MapShapesAndAncestors(theBlock, TopAbs_VERTEX, TopAbs_EDGE, MB);
770   if (MB.Extent() != NBVERTS) {
771     Standard_TypeMismatch::Raise("Block has wrong number of vertices");
772   }
773
774   // 2. Store edges, linking the first face with the second one
775   //    and vertices of the second face
776   TopTools_IndexedMapOfShape aFaceEdges;
777   TopExp::MapShapes(myFaces(1), TopAbs_EDGE, aFaceEdges);
778
779   Standard_Integer i = 1;
780   for (; i <= 4; i++) {
781     // Get i-th vertex of the face 1
782     TopoDS_Shape Vi = myVertices(vertex_id(1, i));
783     if (!MB.Contains(Vi)) {
784       Standard_ConstructionError::Raise("Face does not belong to the block");
785     }
786
787     // Get list of block's edges, sharing this Vertex
788     const TopTools_ListOfShape& anEdgesOfVi = MB.FindFromKey(Vi);
789     TopTools_ListIteratorOfListOfShape anEdgesIter (anEdgesOfVi);
790
791     // Get Edge (from the List), not belonging to the face 1
792     Standard_Boolean isFound = Standard_False;
793     for (; anEdgesIter.More() && !isFound; anEdgesIter.Next()) {
794       if (!aFaceEdges.Contains(anEdgesIter.Value())) {
795         isFound = Standard_True;
796
797         // Store the linking edge
798         TopoDS_Shape aLinkEdge = anEdgesIter.Value();
799         myEdges(side_edge_id(i)) = aLinkEdge;
800
801         // Get another vertex of the linking edge
802         TopoDS_Edge E = TopoDS::Edge(aLinkEdge);
803         TopoDS_Vertex V1, V2;
804         TopExp::Vertices(E, V1, V2, Standard_True);
805
806         // Store the i-th vertex of the second (opposite to the first) face
807         if (V1.IsSame(Vi)) {
808           myVertices(vertex_id(2, i)) = V2;
809         } else {
810           myVertices(vertex_id(2, i)) = V1;
811         }
812       }
813     }
814   }
815
816   // 3. Store edges of the second (opposite to the first) face
817   for (i = 1; i <= 4; i++) {
818     // Get i-th and (i+1)-th vertices of the face 2
819     TopoDS_Shape Vi = myVertices(vertex_id(2, i));
820     TopoDS_Shape Vj = myVertices(vertex_id(2, mod4(i + 1)));
821
822     // Get list of block's edges, sharing Vi
823     const TopTools_ListOfShape& anEdgesOfVi = MB.FindFromKey(Vi);
824     // Get list of block's edges, sharing Vj
825     const TopTools_ListOfShape& anEdgesOfVj = MB.FindFromKey(Vj);
826
827     // Get Edge (from the List), linking this vertex with the next one
828     Standard_Boolean isFound = Standard_False;
829     TopTools_ListIteratorOfListOfShape anEdgesIteri (anEdgesOfVi);
830     for (; anEdgesIteri.More() && !isFound; anEdgesIteri.Next()) {
831
832       TopTools_ListIteratorOfListOfShape anEdgesIterj (anEdgesOfVj);
833       for (; anEdgesIterj.More() && !isFound; anEdgesIterj.Next()) {
834
835         if (anEdgesIteri.Value().IsSame(anEdgesIterj.Value())) {
836           isFound = Standard_True;
837
838           // Store the linking edge
839           myEdges(edge_id(2, i)) = anEdgesIteri.Value();
840         }
841       }
842     }
843   }
844
845   // 4. Store faces of the block
846   TopTools_IndexedDataMapOfShapeListOfShape MBE;
847   MapShapesAndAncestors(theBlock, TopAbs_EDGE, TopAbs_FACE, MBE);
848   if (MBE.Extent() != NBEDGES) {
849     Standard_TypeMismatch::Raise("Block has wrong number of edges");
850   }
851
852   for (i = 2; i <= NBFACES; i++) {
853     TopoDS_Shape Ei1 = myEdges(edge_id(i, 1));
854     TopoDS_Shape Ei2 = myEdges(edge_id(i, 2));
855     const TopTools_ListOfShape& aFacesOfEi1 = MBE.FindFromKey(Ei1);
856     const TopTools_ListOfShape& aFacesOfEi2 = MBE.FindFromKey(Ei2);
857
858     Standard_Boolean isFound = Standard_False;
859     TopTools_ListIteratorOfListOfShape anIterEi1 (aFacesOfEi1);
860     for (; anIterEi1.More() && !isFound; anIterEi1.Next()) {
861
862       TopTools_ListIteratorOfListOfShape anIterEi2 (aFacesOfEi2);
863       for (; anIterEi2.More() && !isFound; anIterEi2.Next()) {
864
865         if (anIterEi1.Value().IsSame(anIterEi2.Value())) {
866           isFound = Standard_True;
867
868           // Store the face, defined by two edges
869           myFaces(i) = anIterEi1.Value();
870         }
871       }
872     }
873   }
874 }
875
876 //=======================================================================
877 //function : InitByTwoFaces
878 //purpose  :
879 //=======================================================================
880 void GEOMImpl_Block6Explorer::InitByTwoFaces (const TopoDS_Shape& theFace1,
881                                               const TopoDS_Shape& theFace2)
882 {
883   if (theFace1.IsSame(theFace2)) {
884     Standard_ConstructionError::Raise("The faces must be different");
885   }
886
887   // Add two given faces in the structure
888   myFaces(1) = theFace1;
889   myFaces(2) = theFace2;
890
891   // Step 1. Order vertices (and edges)
892
893   // 1.1. Ordered vertices and edges of the first face we put in <myVertices>
894
895   // Get wire of the first face
896   TopExp_Explorer wires1 (myFaces(1), TopAbs_WIRE);
897   if (!wires1.More()) {
898     Standard_ConstructionError::Raise("A face for the block has no wires");
899   }
900   TopoDS_Shape aWire1 = wires1.Current();
901   wires1.Next();
902   if (wires1.More()) {
903     Standard_ConstructionError::Raise("A face for the block has more than one wire");
904   }
905
906   BRepTools_WireExplorer aWE1 (TopoDS::Wire(aWire1), TopoDS::Face(myFaces(1)));
907   Standard_Integer nb;
908   for (nb = 1; aWE1.More(); aWE1.Next(), nb++) {
909     if (nb > 4) {
910       Standard_ConstructionError::Raise("A face for the block has more than four edges");
911     }
912     myEdges(edge_id(1, nb)) = aWE1.Current();
913     myVertices(vertex_id(1, nb)) = aWE1.CurrentVertex();
914   }
915   if (nb < 5) {
916     Standard_ConstructionError::Raise("A face for the block has less than four edges");
917   }
918
919   // 1.2. Ordered vertices and edges of the second face we temporarily store
920   // in arrays, to find for them rigth location in <myVertices> on the Step 2.
921
922   // declare arrays
923   TopTools_Array1OfShape aVertis2(1,4); // ordered vertices of the second face
924   TopTools_Array1OfShape anEdges2(1,4); // anEdges2(i) links aVertis2(i) and aVertis2(i+1)
925
926   // Get wire of the second face
927   TopExp_Explorer wires2 (myFaces(2), TopAbs_WIRE);
928   if (!wires2.More()) {
929     Standard_ConstructionError::Raise("A face for the block has no wires");
930   }
931   TopoDS_Shape aWire2 = wires2.Current();
932   wires2.Next();
933   if (wires2.More()) {
934     Standard_ConstructionError::Raise("A face for the block has more than one wire");
935   }
936
937   BRepTools_WireExplorer aWE2 (TopoDS::Wire(aWire2), TopoDS::Face(myFaces(2)));
938   for (nb = 1; aWE2.More(); aWE2.Next(), nb++) {
939     if (nb > 4) {
940       Standard_ConstructionError::Raise("A face for the block has more than four edges");
941     }
942     anEdges2(nb) = aWE2.Current();
943     aVertis2(nb) = aWE2.CurrentVertex();
944   }
945   if (nb < 5) {
946     Standard_ConstructionError::Raise("A face for the block has less than four edges");
947   }
948
949   // Step 2. Find right place in <myVertices> for the <aVertis2>,
950   //         so as to minimize common length of linking edges
951   //         between face 1 and face 2.
952   //         Each linking edge (of four) will link vertices of the
953   //         faces 1 and 2 with equal local numbers.
954   // The right place is defined by:
955   //  - vertex <aVertis2(i_min)>, which will become the first vertex
956   //         of the second face <myVertices(vertex_id(2,1))>
957   //  - orientation of <aVertis2> relatively their future location
958   //         in <myVertices> (s_min = 1 if direct, s_min = -1 if reversed)
959   Standard_Integer i_min = 0, s_min = 0;
960
961   TColgp_Array1OfPnt aPnts1 (1,4); // points of the first face
962   aPnts1(1) = BRep_Tool::Pnt(TopoDS::Vertex(myVertices(vertex_id(1, 1))));
963   aPnts1(2) = BRep_Tool::Pnt(TopoDS::Vertex(myVertices(vertex_id(1, 2))));
964   aPnts1(3) = BRep_Tool::Pnt(TopoDS::Vertex(myVertices(vertex_id(1, 3))));
965   aPnts1(4) = BRep_Tool::Pnt(TopoDS::Vertex(myVertices(vertex_id(1, 4))));
966
967   TColgp_Array1OfPnt aPnts2 (1,4); // points of the second face
968   aPnts2(1) = BRep_Tool::Pnt(TopoDS::Vertex(aVertis2(1)));
969   aPnts2(2) = BRep_Tool::Pnt(TopoDS::Vertex(aVertis2(2)));
970   aPnts2(3) = BRep_Tool::Pnt(TopoDS::Vertex(aVertis2(3)));
971   aPnts2(4) = BRep_Tool::Pnt(TopoDS::Vertex(aVertis2(4)));
972
973   Standard_Real Dist_min = RealLast();
974   // try all possible locations to find the best (with minimum sum distance)
975   Standard_Integer i = 1;
976   for (; i <= 4; i++) {
977     // try direct orientation
978     Standard_Real Dist_plus = aPnts1(1).Distance(aPnts2(i)) +
979                               aPnts1(2).Distance(aPnts2(mod4(i + 1))) +
980                               aPnts1(3).Distance(aPnts2(mod4(i + 2))) +
981                               aPnts1(4).Distance(aPnts2(mod4(i + 3)));
982     if (Dist_plus < Dist_min) {
983       Dist_min = Dist_plus;
984       i_min = i;
985       s_min = 1;
986     }
987
988     // try reversed orientation
989     Standard_Real Dist_minus = aPnts1(1).Distance(aPnts2(i)) +
990                                aPnts1(2).Distance(aPnts2(mod4(i - 1))) +
991                                aPnts1(3).Distance(aPnts2(mod4(i - 2))) +
992                                aPnts1(4).Distance(aPnts2(mod4(i - 3)));
993     if (Dist_minus < Dist_min) {
994       Dist_min = Dist_minus;
995       i_min = i;
996       s_min = - 1;
997     }
998   }
999
1000   // 3. Put vertices and edges of the second face to they
1001   //    permanent location in <myVertices> and <myEdges>
1002   for (i = 1; i <= 4; i++) {
1003     Standard_Integer nb = mod4(i_min + s_min*(i - 1));
1004
1005     if (aPnts1(i).Distance(aPnts2(nb)) < Precision::Confusion()) {
1006       Standard_ConstructionError::Raise("The faces are too close");
1007     }
1008
1009     myVertices(vertex_id(2, i)) = aVertis2(nb);
1010
1011     if (s_min == -1) nb = mod4(nb - 1);
1012     myEdges(edge_id(2, i)) = anEdges2(nb);
1013   }
1014
1015   // check the wires closure
1016   TopoDS_Wire wire1 = TopoDS::Wire(aWire1);
1017   TopoDS_Wire wire2 = TopoDS::Wire(aWire2);
1018   TopoDS_Vertex aV1, aV2;
1019
1020   TopExp::Vertices(wire1, aV1, aV2);
1021   if (!aV1.IsNull() && !aV2.IsNull() && aV1.IsSame(aV2))
1022     aWire1.Closed(true);
1023
1024   TopExp::Vertices(wire2, aV1, aV2);
1025   if (!aV1.IsNull() && !aV2.IsNull() && aV1.IsSame(aV2))
1026     aWire2.Closed(true);
1027
1028   // 4. Generate side surface
1029   if (!aWire1.Closed() || !aWire2.Closed()) {
1030     // BRepOffsetAPI_ThruSections is not applicable on not closed wires
1031     GetFace(3, Standard_True);
1032     GetFace(4, Standard_True);
1033     GetFace(5, Standard_True);
1034     GetFace(6, Standard_True);
1035   } else {
1036     // try to build faces on native surfaces of edges or planar
1037     Standard_Boolean tryThru = Standard_False;
1038     for (Standard_Integer i = 3; i <= 6 && !tryThru; i++) {
1039       Standard_Boolean doMake = Standard_True;
1040       TopoDS_Shape E1 = GetEdge(edge_id(i, 1), doMake);
1041       TopoDS_Shape E2 = GetEdge(edge_id(i, 2), doMake);
1042       TopoDS_Shape E3 = GetEdge(edge_id(i, 3), doMake);
1043       TopoDS_Shape E4 = GetEdge(edge_id(i, 4), doMake);
1044
1045       BRepBuilderAPI_MakeWire MW (TopoDS::Edge(E1),
1046                                   TopoDS::Edge(E2),
1047                                   TopoDS::Edge(E3),
1048                                   TopoDS::Edge(E4));
1049       if (!MW.IsDone()) {
1050         Standard_ConstructionError::Raise("Wire construction failed");
1051       }
1052
1053       BRepBuilderAPI_MakeFace MF (MW, Standard_False);
1054       if (MF.IsDone()) {
1055         myFaces(i) = MF.Shape();
1056       } else {
1057         tryThru = Standard_True;
1058       }
1059     }
1060
1061     // Build side surface by ThruSections algorithm
1062     if (tryThru) {
1063       BRepOffsetAPI_ThruSections THS;
1064       THS.AddWire(TopoDS::Wire(aWire1));
1065       THS.AddWire(TopoDS::Wire(aWire2));
1066       THS.Build();
1067       if (!THS.IsDone()) {
1068         StdFail_NotDone::Raise("Side surface generation failed");
1069       }
1070       for (Standard_Integer i = 1; i <= 4; i++) {
1071         // fill face
1072         myFaces(i+2) = THS.GeneratedFace(myEdges(i));
1073
1074         // fill edge
1075         Standard_Integer ee = side_edge_id(i);
1076         TopTools_IndexedDataMapOfShapeListOfShape MVE;
1077         MapShapesAndAncestors(myFaces(i+2), TopAbs_VERTEX, TopAbs_EDGE, MVE);
1078         FindEdge(myEdges(ee),
1079                  myVertices(vertex_id_edge(ee, 1)),
1080                  myVertices(vertex_id_edge(ee, 2)),
1081                  MVE);
1082       }
1083     }
1084   }
1085 }
1086
1087 //=======================================================================
1088 //function : MapShapesAndAncestors
1089 //purpose  :
1090 //=======================================================================
1091 void GEOMImpl_Block6Explorer::MapShapesAndAncestors (const TopoDS_Shape& S,
1092                                                      const TopAbs_ShapeEnum TS,
1093                                                      const TopAbs_ShapeEnum TA,
1094                                                      TopTools_IndexedDataMapOfShapeListOfShape& M)
1095 {
1096   TopTools_ListOfShape empty;
1097   TopTools_MapOfShape mapA;
1098
1099   // visit ancestors
1100   TopExp_Explorer exa (S,TA);
1101   for (; exa.More(); exa.Next()) {
1102     // visit shapes
1103     const TopoDS_Shape& anc = exa.Current();
1104     if (mapA.Add(anc)) {
1105       TopExp_Explorer exs (anc,TS);
1106       TopTools_MapOfShape mapS;
1107       for (; exs.More(); exs.Next()) {
1108         if (mapS.Add(exs.Current())) {
1109           Standard_Integer index = M.FindIndex(exs.Current());
1110           if (index == 0) index = M.Add(exs.Current(),empty);
1111           M(index).Append(anc);
1112         }
1113       }
1114     }
1115   }
1116
1117   // visit shapes not under ancestors
1118   TopExp_Explorer ex (S,TS,TA);
1119   for (; ex.More(); ex.Next()) {
1120     Standard_Integer index = M.FindIndex(ex.Current());
1121     if (index == 0) index = M.Add(ex.Current(),empty);
1122   }
1123 }
1124
1125 //=======================================================================
1126 //function : IsSimilarEdges
1127 //purpose  :
1128 //=======================================================================
1129 Standard_Boolean GEOMImpl_Block6Explorer::IsSimilarEdges (const TopoDS_Shape& E1,
1130                                                           const TopoDS_Shape& E2)
1131 {
1132   TopoDS_Edge E1e = TopoDS::Edge(E1);
1133   TopoDS_Edge E2e = TopoDS::Edge(E2);
1134   TopoDS_Vertex V11, V12, V21, V22;
1135   TopExp::Vertices(E1e, V11, V12, Standard_True);
1136   TopExp::Vertices(E2e, V21, V22, Standard_True);
1137   if (BRepTools::Compare(V11, V21) && BRepTools::Compare(V12, V22))
1138     return Standard_True;
1139   if (BRepTools::Compare(V11, V22) && BRepTools::Compare(V12, V21))
1140     return Standard_True;
1141
1142   return Standard_False;
1143 }
1144
1145 //=======================================================================
1146 //function : FindEdge
1147 //purpose  :
1148 //=======================================================================
1149 Standard_Integer GEOMImpl_Block6Explorer::FindEdge
1150                    (TopoDS_Shape&       theResult,
1151                     const TopoDS_Shape& V1,
1152                     const TopoDS_Shape& V2,
1153                     const TopTools_IndexedDataMapOfShapeListOfShape& MVE,
1154                     const Standard_Boolean findAll)
1155 {
1156   Standard_Integer isFound = 0;
1157
1158   const TopTools_ListOfShape& anEdgesOfV1 = MVE.FindFromKey(V1);
1159   const TopTools_ListOfShape& anEdgesOfV2 = MVE.FindFromKey(V2);
1160
1161   TopTools_ListIteratorOfListOfShape it1 (anEdgesOfV1);
1162   for (; it1.More(); it1.Next()) {
1163     TopTools_ListIteratorOfListOfShape it2 (anEdgesOfV2);
1164     for (; it2.More(); it2.Next()) {
1165       if (it1.Value().IsSame(it2.Value())) {
1166         isFound++;
1167         theResult = it1.Value();
1168         if (!findAll) return isFound;
1169       }
1170     }
1171   }
1172
1173   return isFound;
1174 }
1175
1176 //=======================================================================
1177 //function : FindFace
1178 //purpose  :
1179 //=======================================================================
1180 Standard_Integer GEOMImpl_Block6Explorer::FindFace
1181                    (TopoDS_Shape&       theResult,
1182                     const TopoDS_Shape& V1,
1183                     const TopoDS_Shape& V2,
1184                     const TopoDS_Shape& V3,
1185                     const TopoDS_Shape& V4,
1186                     const TopTools_IndexedDataMapOfShapeListOfShape& MVF,
1187                     const Standard_Boolean findAll)
1188 {
1189   Standard_Integer isFound = Standard_False;
1190
1191   const TopTools_ListOfShape& aFacesOfV1 = MVF.FindFromKey(V1);
1192   const TopTools_ListOfShape& aFacesOfV2 = MVF.FindFromKey(V2);
1193   const TopTools_ListOfShape& aFacesOfV3 = MVF.FindFromKey(V3);
1194   const TopTools_ListOfShape& aFacesOfV4 = MVF.FindFromKey(V4);
1195
1196   TopTools_ListIteratorOfListOfShape it1 (aFacesOfV1);
1197   for (; it1.More(); it1.Next()) {
1198     TopTools_ListIteratorOfListOfShape it2 (aFacesOfV2);
1199     for (; it2.More(); it2.Next()) {
1200       if (it1.Value().IsSame(it2.Value())) {
1201         TopTools_ListIteratorOfListOfShape it3 (aFacesOfV3);
1202         for (; it3.More(); it3.Next()) {
1203           if (it1.Value().IsSame(it3.Value())) {
1204             TopTools_ListIteratorOfListOfShape it4 (aFacesOfV4);
1205             for (; it4.More(); it4.Next()) {
1206               if (it1.Value().IsSame(it4.Value())) {
1207                 isFound++;
1208                 theResult = it1.Value();
1209                 if (!findAll) return isFound;
1210               }
1211             }
1212           }
1213         }
1214       }
1215     }
1216   }
1217
1218   return isFound;
1219 }
1220
1221 //=======================================================================
1222 //function : MakeFace
1223 //purpose  :
1224 //=======================================================================
1225 TCollection_AsciiString GEOMImpl_Block6Explorer::MakeFace (const TopoDS_Wire&     theWire,
1226                                                            const Standard_Boolean isPlanarWanted,
1227                                                            TopoDS_Shape&          theResult)
1228 {
1229   if (!isPlanarWanted)
1230     return MakeAnyFace(theWire, theResult);
1231
1232   // Try to build a planar face.
1233
1234   // If required tolerance increase will be
1235   // higher than PLANAR_FACE_MAX_TOLERANCE,
1236   // we will try to build a non-planar face.
1237
1238   TCollection_AsciiString aWarning;
1239
1240   // Workaround for Mantis issue 0020956
1241
1242   // Count the number of points in the wire.
1243   // Collect the first three points.
1244   gp_Pnt p1, p2, p3;
1245   bool is3Pnts (false);
1246   bool p1set(false), p2set(false), p3set(false);
1247   BRepTools_WireExplorer wexpl (theWire);
1248   for (; wexpl.More(); wexpl.Next()) {
1249     if (!p1set) {
1250       p1set = true;
1251       p1 = BRep_Tool::Pnt(wexpl.CurrentVertex());
1252     }
1253     else if (!p2set) {
1254       p2set = true;
1255       p2 = BRep_Tool::Pnt(wexpl.CurrentVertex());
1256     }
1257     else if (!p3set) {
1258       p3set = true;
1259       is3Pnts = true;
1260       p3 = BRep_Tool::Pnt(wexpl.CurrentVertex());
1261     }
1262     else {
1263       is3Pnts = false;
1264       break;
1265     }
1266   }
1267
1268   // Construct a plane for the case of three points in the wire.
1269   gp_Pln plane;
1270   if (is3Pnts) {
1271     gce_MakePln mkPln (p1, p2, p3);
1272     if (mkPln.IsDone()) {
1273       plane = mkPln.Value();
1274     }
1275     else {
1276       is3Pnts = false;
1277     }
1278   }
1279
1280   // Construct a face based on the plane (in case of three points in the wire) or
1281   // allow MakeFace to build the plane itself (in case of the number of points is greater than 3).
1282   if (is3Pnts) {
1283     BRepBuilderAPI_MakeFace MK (plane, theWire, isPlanarWanted);
1284     if (MK.IsDone()) {
1285       theResult = MK.Shape();
1286       return aWarning;
1287     }
1288   }
1289   else {
1290     BRepBuilderAPI_MakeFace MK (theWire, isPlanarWanted);
1291     if (MK.IsDone()) {
1292       theResult = MK.Shape();
1293       return aWarning;
1294     }
1295   }
1296
1297   // try to update wire tolerances to build a planar face
1298
1299   // Find a deviation
1300   Standard_Real aToleranceReached, aTol;
1301   BRepLib_FindSurface aFS;
1302   aFS.Init(theWire, -1., isPlanarWanted);
1303   aToleranceReached = aFS.ToleranceReached();
1304   aTol = aFS.Tolerance();
1305
1306   if (!aFS.Found()) {
1307     aFS.Init(theWire, aToleranceReached, isPlanarWanted);
1308     if (!aFS.Found()) return aWarning;
1309     aToleranceReached = aFS.ToleranceReached();
1310     aTol = aFS.Tolerance();
1311   }
1312   aTol = Max(1.2 * aToleranceReached, aTol);
1313
1314   // Mantis issue 0021432: EDF GEOM: Faces with huge tolerance can be built in GEOM
1315   if (aTol > PLANAR_FACE_MAX_TOLERANCE) {
1316     aWarning = MakeAnyFace(theWire, theResult);
1317     if (aWarning.IsEmpty() && !theResult.IsNull())
1318       aWarning = "MAKE_FACE_TOLERANCE_TOO_BIG";
1319     return aWarning;
1320   }
1321
1322   // Copy the wire, bacause it can be updated with very-very big tolerance here
1323   BRepBuilderAPI_Copy aMC (theWire);
1324   if (!aMC.IsDone()) return aWarning;
1325   TopoDS_Wire aWire = TopoDS::Wire(aMC.Shape());
1326   // Update tolerances to <aTol>
1327   BRep_Builder B;
1328   for (TopExp_Explorer expE (aWire, TopAbs_EDGE); expE.More(); expE.Next()) {
1329     TopoDS_Edge anE = TopoDS::Edge(expE.Current());
1330     B.UpdateEdge(anE, aTol);
1331   }
1332   for (TopExp_Explorer expV (aWire, TopAbs_VERTEX); expV.More(); expV.Next()) {
1333     TopoDS_Vertex aV = TopoDS::Vertex(expV.Current());
1334     B.UpdateVertex(aV, aTol);
1335   }
1336   //BRepLib::UpdateTolerances(aWire);
1337   // Build face
1338   BRepBuilderAPI_MakeFace MK1 (aWire, isPlanarWanted);
1339   if (MK1.IsDone()) {
1340     theResult = MK1.Shape();
1341     // Mantis issue 0021432: EDF GEOM: Faces with huge tolerance can be built in GEOM
1342     //if (aTol > PLANAR_FACE_MAX_TOLERANCE)
1343     //  aWarning = "MAKE_FACE_TOLERANCE_TOO_BIG";
1344   }
1345
1346   return aWarning;
1347 }
1348
1349 //=======================================================================
1350 //function : MakeAnyFace
1351 //purpose  :
1352 //=======================================================================
1353 TCollection_AsciiString GEOMImpl_Block6Explorer::MakeAnyFace (const TopoDS_Wire& theWire,
1354                                                               TopoDS_Shape&      theResult)
1355 {
1356   TCollection_AsciiString aWarning;
1357
1358   // try to build a face on any surface under the edges of the wire
1359   BRepBuilderAPI_MakeFace MK (theWire, Standard_False);
1360   if (MK.IsDone()) {
1361     theResult = MK.Shape();
1362     return aWarning;
1363   }
1364
1365   // try to construct filling surface
1366   BRepOffsetAPI_MakeFilling MF;
1367
1368   Standard_Integer nbEdges = 0;
1369   BRepTools_WireExplorer aWE (theWire);
1370   for (; aWE.More(); aWE.Next(), nbEdges++) {
1371     MF.Add(TopoDS::Edge(aWE.Current()), GeomAbs_C0);
1372   }
1373
1374   MF.Build();
1375   if (!MF.IsDone()) {
1376     aWarning = "BRepOffsetAPI_MakeFilling failed";
1377     return aWarning;
1378   }
1379
1380   // Result of filling
1381   TopoDS_Shape aFace = MF.Shape();
1382
1383   // 12.04.2006 for PAL12149 begin
1384   Handle(Geom_Surface) aGS = BRep_Tool::Surface(TopoDS::Face(aFace));
1385
1386 #ifdef MAKE_FACE_UPGRADE_PCURVES
1387   BRep_Builder BB;
1388   TopoDS_Iterator itw(theWire);
1389   for (; itw.More(); itw.Next())
1390   {
1391     const TopoDS_Edge& anEdge = TopoDS::Edge(itw.Value());
1392     TopoDS_Edge NewEdge = TopoDS::Edge(MF.Generated(anEdge).First());
1393     Standard_Real fpar, lpar;
1394     Handle(Geom2d_Curve) NewPCurve = BRep_Tool::CurveOnSurface(NewEdge, TopoDS::Face(aFace), fpar, lpar);
1395     TopLoc_Location aLoc;
1396     Standard_Real NewTol = BRep_Tool::Tolerance(NewEdge);
1397     BB.UpdateEdge(anEdge, NewPCurve, aGS, aLoc, NewTol);
1398   }
1399 #endif
1400
1401   BRepBuilderAPI_MakeFace MK1 (aGS, theWire);
1402   if (MK1.IsDone()) {
1403     TopoDS_Shape aFace1 = MK1.Shape();
1404
1405     BRepCheck_Analyzer ana (aFace1, false);
1406     if (!ana.IsValid()) {
1407       TopoDS_Shape aFace2;
1408       ShHealOper_ShapeProcess aHealer;
1409       aHealer.Perform(aFace1, aFace2);
1410       if (aHealer.isDone())
1411         theResult = aFace2;
1412     }
1413   }
1414   // 12.04.2006 for PAL12149 end
1415
1416   if (!theResult.IsNull()) {
1417     // try to deal with result of BRepBuilderAPI_MakeFace + ShHealOper_ShapeProcess
1418 #if OCC_VERSION_LARGE >= 0x06080000
1419 #ifdef MAKE_FACE_PCURVES_FIX_TOLERANCE
1420     // check and fix pcurves, if necessary
1421     Standard_Real aT, aTolE, aD, aDMax;
1422     TopExp_Explorer aExpF, aExpE;
1423     NCollection_DataMap<TopoDS_Shape, Standard_Real, TopTools_ShapeMapHasher> aDMETol;
1424     aExpF.Init(theResult, TopAbs_FACE);
1425     for (; aExpF.More(); aExpF.Next()) {
1426       const TopoDS_Face& aF = *(TopoDS_Face*)&aExpF.Current();
1427       aExpE.Init(aF, TopAbs_EDGE);
1428       for (; aExpE.More(); aExpE.Next()) {
1429         const TopoDS_Edge& aE = *(TopoDS_Edge*)&aExpE.Current();
1430         if (!BOPTools_AlgoTools::ComputeTolerance(aF, aE, aDMax, aT)) continue;
1431         aTolE = BRep_Tool::Tolerance(aE);
1432         if (aDMax < aTolE) continue;
1433         if (aDMETol.IsBound(aE)) {
1434           aD = aDMETol.Find(aE);
1435           if (aDMax > aD) {
1436             aDMETol.UnBind(aE);
1437             aDMETol.Bind(aE, aDMax);
1438           }
1439         }
1440         else {
1441           aDMETol.Bind(aE, aDMax);
1442         }
1443       }
1444     }
1445     NCollection_DataMap<TopoDS_Shape, Standard_Real, TopTools_ShapeMapHasher>::Iterator aDMETolIt(aDMETol);
1446     ShapeFix_ShapeTolerance sat;
1447     for (; aDMETolIt.More(); aDMETolIt.Next()) {
1448       sat.LimitTolerance(aDMETolIt.Key(), aDMETolIt.Value());
1449     }
1450 #endif
1451 #endif
1452   }
1453   else {
1454     // try to deal with pure result of BRepOffsetAPI_MakeFilling
1455
1456     // Update tolerance
1457     Standard_Real aTol = MF.G0Error();
1458
1459     TColgp_Array1OfPnt aPnts (1,nbEdges); // points of the given wire
1460     BRepTools_WireExplorer aWE1 (theWire);
1461     Standard_Integer vi = 1;
1462     for (; aWE1.More() && vi <= nbEdges; aWE1.Next(), vi++) {
1463       aPnts(vi) = BRep_Tool::Pnt(TopoDS::Vertex(aWE1.CurrentVertex()));
1464     }
1465
1466     // Find maximum deviation in vertices
1467     TopExp_Explorer exp (aFace, TopAbs_VERTEX);
1468     TopTools_MapOfShape mapShape;
1469     for (; exp.More(); exp.Next()) {
1470       if (mapShape.Add(exp.Current())) {
1471         TopoDS_Vertex aV = TopoDS::Vertex(exp.Current());
1472         Standard_Real aTolV = BRep_Tool::Tolerance(aV);
1473         gp_Pnt aP = BRep_Tool::Pnt(aV);
1474         Standard_Real min_dist = aP.Distance(aPnts(1));
1475         for (vi = 2; vi <= nbEdges; vi++) {
1476           min_dist = Min(min_dist, aP.Distance(aPnts(vi)));
1477         }
1478         aTol = Max(aTol, aTolV);
1479         aTol = Max(aTol, min_dist);
1480       }
1481     }
1482
1483     if ((*((Handle(BRep_TFace)*)&aFace.TShape()))->Tolerance() < aTol) {
1484       (*((Handle(BRep_TFace)*)&aFace.TShape()))->Tolerance(aTol);
1485     }
1486     theResult = aFace;
1487   }
1488
1489   return aWarning;
1490 }