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