]> SALOME platform Git repositories - modules/geom.git/blob - src/GEOMImpl/GEOMImpl_BlockDriver.cxx
Salome HOME
Add new command GetShapesOnBox.
[modules/geom.git] / src / GEOMImpl / GEOMImpl_BlockDriver.cxx
1 // Copyright (C) 2005  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
2 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
3 // 
4 // This library is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU Lesser General Public
6 // License as published by the Free Software Foundation; either 
7 // version 2.1 of the License.
8 // 
9 // This library is distributed in the hope that it will be useful 
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
12 // Lesser General Public License for more details.
13 //
14 // You should have received a copy of the GNU Lesser General Public  
15 // License along with this library; if not, write to the Free Software 
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
17 //
18 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
19 //
20
21 #include <Standard_Stream.hxx>
22
23 #include <BRepOffsetAPI_MakeFilling.hxx>
24
25 #include <GEOMImpl_BlockDriver.hxx>
26 #include <GEOMImpl_IBlocks.hxx>
27 #include <GEOMImpl_IBlockTrsf.hxx>
28 #include <GEOMImpl_GlueDriver.hxx>
29 #include <GEOMImpl_Types.hxx>
30 #include <GEOMImpl_ILocalOperations.hxx>
31 #include <GEOMImpl_Block6Explorer.hxx>
32 #include <GEOMImpl_IBlocksOperations.hxx>
33
34 #include <GEOM_Function.hxx>
35
36 #include <ShHealOper_Sewing.hxx>
37 #include <NMTAlgo_Splitter1.hxx>
38 #include <BlockFix_BlockFixAPI.hxx>
39
40 #include "utilities.h"
41
42 #include <TNaming_CopyShape.hxx>
43
44 #include <BRepLib.hxx>
45 #include <BRep_Tool.hxx>
46 #include <BRepTools.hxx>
47 #include <BRepGProp.hxx>
48 #include <BRep_Builder.hxx>
49 #include <BRepTools_Quilt.hxx>
50 #include <BRepTools_WireExplorer.hxx>
51 #include <BRepBuilderAPI_MakeEdge.hxx>
52 #include <BRepBuilderAPI_MakeWire.hxx>
53 #include <BRepBuilderAPI_MakePolygon.hxx>
54 #include <BRepBuilderAPI_Transform.hxx>
55 #include <BRepClass_FaceClassifier.hxx>
56 #include <BRepClass3d_SolidClassifier.hxx>
57 #include <BRepExtrema_ExtPF.hxx>
58 #include <BRepExtrema_DistShapeShape.hxx>
59
60 #include <TopAbs.hxx>
61 #include <TopoDS.hxx>
62 #include <TopoDS_Shape.hxx>
63 #include <TopoDS_Edge.hxx>
64 #include <TopoDS_Wire.hxx>
65 #include <TopoDS_Shell.hxx>
66 #include <TopoDS_Solid.hxx>
67 #include <TopoDS_Compound.hxx>
68 #include <TopoDS_Iterator.hxx>
69 #include <TopExp.hxx>
70 #include <TopExp_Explorer.hxx>
71 #include <TopTools_MapOfShape.hxx>
72 #include <TopTools_MapIteratorOfMapOfShape.hxx>
73 #include <TopTools_Array1OfShape.hxx>
74 #include <TopTools_SequenceOfShape.hxx>
75 #include <TopTools_ListOfShape.hxx>
76 #include <TopTools_ListIteratorOfListOfShape.hxx>
77 #include <TopTools_IndexedMapOfShape.hxx>
78 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
79
80 #include <GProp_GProps.hxx>
81
82 #include <gp.hxx>
83 #include <gp_Pnt.hxx>
84 #include <gp_Ax3.hxx>
85 #include <Precision.hxx>
86 #include <TColgp_Array1OfPnt.hxx>
87 #include <TColStd_Array1OfInteger.hxx>
88 #include <TColStd_IndexedDataMapOfTransientTransient.hxx>
89 #include <StdFail_NotDone.hxx>
90 #include <Standard_NullObject.hxx>
91 #include <Standard_TypeMismatch.hxx>
92 #include <Standard_ConstructionError.hxx>
93
94 //=======================================================================
95 //function : GetID
96 //purpose  :
97 //=======================================================================
98 const Standard_GUID& GEOMImpl_BlockDriver::GetID()
99 {
100   static Standard_GUID aBlockDriver("FF1BBB67-5D14-4df2-980B-3A668264EA16");
101   return aBlockDriver;
102 }
103
104
105 //=======================================================================
106 //function : GEOMImpl_BlockDriver
107 //purpose  :
108 //=======================================================================
109 GEOMImpl_BlockDriver::GEOMImpl_BlockDriver()
110 {
111 }
112
113 //=======================================================================
114 //function : Execute
115 //purpose  :
116 //=======================================================================
117 Standard_Integer GEOMImpl_BlockDriver::Execute(TFunction_Logbook& log) const
118 {
119   if (Label().IsNull()) return 0;
120   Handle(GEOM_Function) aFunction = GEOM_Function::GetFunction(Label());
121
122   Standard_Integer aType = aFunction->GetType();
123
124   TopoDS_Shape aShape;
125   BRep_Builder B;
126
127   Standard_Real prec = Precision::Confusion();
128
129   Standard_Integer aNbSub = 0;
130   if (aType == BLOCK_COMPOUND_GLUE) {
131
132     aNbSub = 1;
133
134   } else if (aType == BLOCK_FACE_TWO_EDGES ||
135              aType == BLOCK_TWO_FACES) {
136
137     aNbSub = 2;
138
139   } else if (aType == BLOCK_FACE_FOUR_PNT ||
140              aType == BLOCK_FACE_FOUR_EDGES) {
141
142     aNbSub = 4;
143
144   } else if (aType == BLOCK_SIX_FACES) {
145
146     aNbSub = 6;
147
148   } else {
149   }
150
151   if (aNbSub > 0) {
152     GEOMImpl_IBlocks aCI (aFunction);
153     Handle(TColStd_HSequenceOfTransient) aShapes = aCI.GetShapes();
154     Standard_Integer nbshapes = aShapes->Length();
155
156     if (nbshapes != aNbSub) {
157       Standard_TypeMismatch::Raise
158         ("Number of elements for object construction does not correspond to the used constructor");
159     }
160
161     TopTools_Array1OfShape anArgs (1, aNbSub);
162     Standard_Integer argi;
163     for (argi = 1; argi <= aNbSub; argi++) {
164       Handle(GEOM_Function) aRef = Handle(GEOM_Function)::DownCast(aShapes->Value(argi));
165       TopoDS_Shape anArg = aRef->GetValue();
166       if (anArg.IsNull()) {
167         Standard_NullObject::Raise("Null shape is given as argument");
168       }
169       anArgs(argi) = anArg;
170     }
171
172     if (aType == BLOCK_FACE_FOUR_EDGES) {
173
174       // Make face from four edges
175       if (anArgs(1).ShapeType() != TopAbs_EDGE || anArgs(2).ShapeType() != TopAbs_EDGE ||
176           anArgs(3).ShapeType() != TopAbs_EDGE || anArgs(4).ShapeType() != TopAbs_EDGE) {
177         Standard_TypeMismatch::Raise("Shape for face construction is not an edge");
178       }
179
180       // count corner vertices
181       TopTools_MapOfShape aVertMap;
182       for (Standard_Integer ii = 1; ii <= 4; ii++) {
183         TopoDS_Edge anEdge = TopoDS::Edge(anArgs(ii));
184         TopoDS_Vertex V1, V2;
185         TopExp::Vertices(anEdge, V1, V2, Standard_True);
186         if (V1.IsNull() || V2.IsNull()) {
187           Standard_NullObject::Raise("Bad edge for face construction: vertex is not defined");
188         }
189         if (BRepTools::Compare(V1,V2)) {
190           Standard_ConstructionError::Raise("Edge ends are too close");
191         }
192         Standard_Boolean isCoin1 = Standard_False, isCoin2 = Standard_False;
193         TopTools_MapIteratorOfMapOfShape anIter (aVertMap);
194         for (; anIter.More(); anIter.Next()) {
195           TopoDS_Vertex V = TopoDS::Vertex(anIter.Key());
196           if (BRepTools::Compare(V,V1)) isCoin1 = Standard_True;
197           if (BRepTools::Compare(V,V2)) isCoin2 = Standard_True;
198         }
199         if (!isCoin1) aVertMap.Add(V1);
200         if (!isCoin2) aVertMap.Add(V2);
201       }
202       if (aVertMap.Extent() != 4) {
203         Standard_ConstructionError::Raise("The edges must form a closed wire");
204       }
205
206       TopoDS_Edge anEdge1 = TopoDS::Edge(anArgs(1));
207       TopoDS_Edge anEdge2 = TopoDS::Edge(anArgs(2));
208       TopoDS_Edge anEdge3 = TopoDS::Edge(anArgs(3));
209       TopoDS_Edge anEdge4 = TopoDS::Edge(anArgs(4));
210
211       // check, if anEdge1 has common/coincident vertex with anEdge2,
212       Standard_Boolean isConnected12 = Standard_False;
213       TopoDS_Vertex V11, V12, V21, V22;
214       TopExp::Vertices(anEdge1, V11, V12, Standard_True);
215       TopExp::Vertices(anEdge2, V21, V22, Standard_True);
216       if (BRepTools::Compare(V11,V21) || BRepTools::Compare(V11,V22) ||
217           BRepTools::Compare(V12,V21) || BRepTools::Compare(V12,V22)) {
218         // the edges have common vertex
219         isConnected12 = Standard_True;
220       }
221
222       // build wire in right order, corresponding to edges connexity
223       BRepBuilderAPI_MakeWire* MW;
224       if (isConnected12)
225         MW = new BRepBuilderAPI_MakeWire(anEdge1, anEdge2, anEdge3, anEdge4);
226       else
227         MW = new BRepBuilderAPI_MakeWire(anEdge1, anEdge3, anEdge2, anEdge4);
228
229       if (!MW->IsDone()) {
230         Standard_ConstructionError::Raise
231           ("Impossible to build a connected wire from the given edges");
232       }
233       TopoDS_Wire aWire = *MW;
234       delete MW; 
235       if (!aWire.Closed()) {
236         Standard_ConstructionError::Raise
237           ("Impossible to build a closed wire from the given edges");
238       }
239
240       // try to build face on the wire
241       GEOMImpl_Block6Explorer::MakeFace(aWire, Standard_False, aShape);
242       if (aShape.IsNull()) {
243         Standard_ConstructionError::Raise("Face construction failed");
244       }
245
246     } else if (aType == BLOCK_FACE_TWO_EDGES) {
247
248       // Make face from two opposite edges
249       if (anArgs(1).ShapeType() != TopAbs_EDGE ||
250           anArgs(2).ShapeType() != TopAbs_EDGE) {
251         Standard_TypeMismatch::Raise("Shape for face construction is not an edge");
252       }
253
254       TopoDS_Edge anEdge1 = TopoDS::Edge(anArgs(1));
255       TopoDS_Edge anEdge2 = TopoDS::Edge(anArgs(2));
256
257       if (anEdge1.IsSame(anEdge2)) {
258         Standard_ConstructionError::Raise("The edges must be different");
259       }
260
261       // create two edges, linking ends of the given edges
262       TopoDS_Vertex V11, V12, V21, V22;
263       TopExp::Vertices(anEdge1, V11, V12, Standard_True);
264       TopExp::Vertices(anEdge2, V21, V22, Standard_True);
265       if (V11.IsNull() || V12.IsNull() ||
266           V21.IsNull() || V22.IsNull()) {
267         Standard_NullObject::Raise("Bad edge for face construction: vertex is not defined");
268       }
269       gp_Pnt P11 = BRep_Tool::Pnt(V11);
270       gp_Pnt P12 = BRep_Tool::Pnt(V12);
271       gp_Pnt P21 = BRep_Tool::Pnt(V21);
272       gp_Pnt P22 = BRep_Tool::Pnt(V22);
273
274       if (P11.Distance(P21) < prec || P12.Distance(P22) < prec ||
275           P11.Distance(P22) < prec || P12.Distance(P21) < prec) {
276         Standard_ConstructionError::Raise("Given edges have too close ends");
277       }
278
279       Standard_Real per11 = P11.Distance(P21) + P12.Distance(P22);
280       Standard_Real per12 = P11.Distance(P22) + P12.Distance(P21);
281
282       TopoDS_Edge anEdge3;
283       TopoDS_Edge anEdge4;
284       if (per11 < per12) {
285         anEdge3 = BRepBuilderAPI_MakeEdge(V11, V21);
286         anEdge4 = BRepBuilderAPI_MakeEdge(V12, V22);
287       } else {
288         anEdge3 = BRepBuilderAPI_MakeEdge(V11, V22);
289         anEdge4 = BRepBuilderAPI_MakeEdge(V12, V21);
290       }
291
292       // build a wire
293       BRepBuilderAPI_MakeWire MW (anEdge1, anEdge3, anEdge2, anEdge4);
294       if (!MW.IsDone()) {
295         Standard_ConstructionError::Raise("Wire construction failed");
296       }
297
298       // try to build face on the wire
299       GEOMImpl_Block6Explorer::MakeFace(MW, Standard_False, aShape);
300       if (aShape.IsNull()) {
301         Standard_ConstructionError::Raise("Face construction failed");
302       }
303
304     } else if (aType == BLOCK_FACE_FOUR_PNT) {
305
306       // Make face from four corner vertices
307       if (anArgs(1).ShapeType() != TopAbs_VERTEX ||
308           anArgs(2).ShapeType() != TopAbs_VERTEX ||
309           anArgs(3).ShapeType() != TopAbs_VERTEX ||
310           anArgs(4).ShapeType() != TopAbs_VERTEX) {
311         Standard_TypeMismatch::Raise("Shape for face construction is not a vertex");
312       }
313
314       TopoDS_Vertex V1 = TopoDS::Vertex(anArgs(1));
315       TopoDS_Vertex V2 = TopoDS::Vertex(anArgs(2));
316       TopoDS_Vertex V3 = TopoDS::Vertex(anArgs(3));
317       TopoDS_Vertex V4 = TopoDS::Vertex(anArgs(4));
318
319       gp_Pnt P1 = BRep_Tool::Pnt(V1);
320       gp_Pnt P2 = BRep_Tool::Pnt(V2);
321       gp_Pnt P3 = BRep_Tool::Pnt(V3);
322       gp_Pnt P4 = BRep_Tool::Pnt(V4);
323
324       if (P1.Distance(P2) < prec || P1.Distance(P3) < prec ||
325           P1.Distance(P4) < prec || P2.Distance(P3) < prec ||
326           P2.Distance(P4) < prec || P3.Distance(P4) < prec) {
327         Standard_ConstructionError::Raise("Four not coincident points must be given");
328       }
329
330       // calculate perimeters
331       Standard_Real per1234 = P1.Distance(P2) + P2.Distance(P3) +
332                               P3.Distance(P4) + P4.Distance(P1);
333       Standard_Real per1243 = P1.Distance(P2) + P2.Distance(P4) +
334                               P4.Distance(P3) + P3.Distance(P1);
335       Standard_Real per1324 = P1.Distance(P3) + P3.Distance(P2) +
336                               P2.Distance(P4) + P4.Distance(P1);
337
338       // order vertices
339       if (per1243 < per1234 && per1243 < per1324) {
340         TopoDS_Vertex Vtmp = V3;
341         V3 = V4;
342         V4 = Vtmp;
343       } else if (per1324 < per1234 && per1324 < per1243) {
344         TopoDS_Vertex Vtmp = V3;
345         V3 = V2;
346         V2 = Vtmp;
347       } else {
348       }
349
350       // build wire
351       BRepBuilderAPI_MakePolygon aMkPoly (V1, V2, V3, V4, Standard_True);
352       if (!aMkPoly.IsDone()) {
353         Standard_ConstructionError::Raise("Polygon construction failed");
354       }
355
356       // try to build face on the wire
357       GEOMImpl_Block6Explorer::MakeFace(aMkPoly, Standard_False, aShape);
358       if (aShape.IsNull()) {
359         Standard_ConstructionError::Raise("Face construction failed");
360       }
361
362     } else if (aType == BLOCK_SIX_FACES || aType == BLOCK_TWO_FACES) {
363
364       BRepTools_Quilt Glue;
365
366       if (aType == BLOCK_SIX_FACES) {
367
368         // Make block (hexahedral solid) from six faces
369         for (Standard_Integer ind = 1; ind <= nbshapes; ind++) {
370           if (anArgs(ind).ShapeType() != TopAbs_FACE) {
371             Standard_TypeMismatch::Raise("Shape for block construction is not a face");
372           }
373           Glue.Add(anArgs(ind));
374         }
375
376       } else {
377
378         // Make block (hexahedral solid) from two opposite faces
379         if (anArgs(1).ShapeType() != TopAbs_FACE ||
380             anArgs(2).ShapeType() != TopAbs_FACE) {
381           Standard_TypeMismatch::Raise("Shape for block construction is not a face");
382         }
383
384         // Get wires of the given faces
385         TopExp_Explorer wires1 (anArgs(1), TopAbs_WIRE);
386         TopExp_Explorer wires2 (anArgs(2), TopAbs_WIRE);
387         if (!wires1.More() || !wires2.More()) {
388           Standard_ConstructionError::Raise("A face for the block has no wires");
389         }
390         TopoDS_Shape aWire1 = wires1.Current();
391         TopoDS_Shape aWire2 = wires2.Current();
392         wires1.Next();
393         wires2.Next();
394         if (wires1.More() || wires2.More()) {
395           Standard_ConstructionError::Raise("A face for the block has more than one wire");
396         }
397
398         GEOMImpl_Block6Explorer aBlockTool;
399         aBlockTool.InitByTwoFaces(anArgs(1), anArgs(2));
400
401         // Construct the linking faces and add them in the gluing tool
402         Glue.Add(anArgs(1));
403         Glue.Add(aBlockTool.GetFace(3, Standard_True));
404         Glue.Add(aBlockTool.GetFace(4, Standard_True));
405         Glue.Add(aBlockTool.GetFace(5, Standard_True));
406         Glue.Add(aBlockTool.GetFace(6, Standard_True));
407         Glue.Add(anArgs(2));
408       }
409
410       TopExp_Explorer exp (Glue.Shells(), TopAbs_SHELL);
411       Standard_Integer ish = 0;
412       TopTools_MapOfShape mapShape;
413       for (; exp.More(); exp.Next()) {
414         if (mapShape.Add(exp.Current())) {
415           aShape = exp.Current();
416           ish++;
417         }
418       }
419
420       if (ish > 1) {
421         aShape = Glue.Shells();
422         Standard_Real aTol = prec; // Precision::Confusion()
423         TopExp_Explorer expF (aShape, TopAbs_FACE);
424         TopTools_MapOfShape mapF;
425         TopoDS_Shell Shell;
426         B.MakeShell(Shell);
427         for (; expF.More(); expF.Next()) {
428           if (mapF.Add(expF.Current())) {
429             B.Add(Shell, expF.Current());
430             Standard_Real aToler = BRep_Tool::Tolerance(TopoDS::Face(expF.Current()));
431             if (aToler > aTol)
432               aTol = aToler;
433           }
434         }
435         ShHealOper_Sewing aHealer (Shell, aTol);
436         if (aHealer.Perform())
437           aShape = aHealer.GetResultShape();
438         else
439           Standard_ConstructionError::Raise
440             ("Impossible to build a connected shell on the given faces");
441       }
442
443       if (aType == BLOCK_SIX_FACES) {
444         if (!aShape.Closed()) {
445           Standard_ConstructionError::Raise
446             ("Impossible to build a closed shell on the given faces");
447         }
448       }
449
450       TopoDS_Solid Sol;
451       B.MakeSolid(Sol);
452       B.Add(Sol, aShape);
453       BRepClass3d_SolidClassifier SC (Sol);
454       SC.PerformInfinitePoint(prec);
455       if (SC.State() == TopAbs_IN) {
456         B.MakeSolid(Sol);
457         B.Add(Sol, aShape.Reversed());
458       }
459       aShape = Sol;
460       BRepLib::SameParameter(aShape, 1.E-5, Standard_True);
461
462     } else if (aType == BLOCK_COMPOUND_GLUE) {
463
464       // Make blocks compound from a compound
465       if (anArgs(1).ShapeType() != TopAbs_COMPOUND &&
466           anArgs(2).ShapeType() != TopAbs_COMPSOLID) {
467         Standard_TypeMismatch::Raise("Not a compound given");
468       }
469
470       TopoDS_Shape aCompound = anArgs(1);
471
472       // Glue coincident faces and edges (with Partition algorithm).
473       NMTAlgo_Splitter1 PS;
474       PS.AddShape(aCompound);
475       PS.Compute();
476       PS.SetRemoveWebs(Standard_False);
477 //      PS.Build(aCompound.ShapeType());
478       PS.Build(TopAbs_SOLID);
479
480       aShape = PS.Shape();
481     } else {
482     }
483
484   } else { // Multi-transformations and compound improving
485
486     if (aType == BLOCK_REMOVE_EXTRA ||
487         aType == BLOCK_COMPOUND_IMPROVE) {
488
489       GEOMImpl_IBlockTrsf aCI (aFunction);
490       Handle(GEOM_Function) aRefShape = aCI.GetOriginal();
491       TopoDS_Shape aBlockOrComp = aRefShape->GetValue();
492       if (aBlockOrComp.IsNull()) {
493         Standard_NullObject::Raise("Null Shape given");
494       }
495
496       // 1. Improve solids with seam and/or degenerated edges
497       BlockFix_BlockFixAPI aTool;
498       //aTool.Tolerance() = toler;
499       aTool.SetShape(aBlockOrComp);
500       aTool.Perform();
501
502       if (aType == BLOCK_REMOVE_EXTRA) {
503
504         aShape = aTool.Shape();
505         if (aShape == aBlockOrComp) {
506           MESSAGE("No modifications have been done");
507         }
508
509       } else { // aType == BLOCK_COMPOUND_IMPROVE
510
511         TopoDS_Shape aFixedExtra = aTool.Shape();
512
513         // 2. Separate non-blocks
514         TopTools_ListOfShape BLO; // All blocks from the given compound
515         TopTools_ListOfShape NOT; // Not blocks
516         TopTools_ListOfShape EXT; // Hexahedral solids, having degenerated and/or seam edges
517         GEOMImpl_IBlocksOperations::AddBlocksFrom(aFixedExtra, BLO, NOT, EXT);
518
519         if (NOT.Extent() > 0) {
520           MESSAGE("Some non-blocks have been removed");
521         }
522
523         // 3. Warn about staying extra-edges
524         if (EXT.Extent() > 0) {
525           MESSAGE("Warning: Not all seam or degenerated edges was removed");
526         }
527
528         // ??? Throw away standalone blocks ???
529
530         // 4. Create compound of all blocks
531         TopoDS_Compound aComp;
532         BRep_Builder BB;
533         BB.MakeCompound(aComp);
534         TopTools_ListIteratorOfListOfShape BLOit (BLO);
535         for (; BLOit.More(); BLOit.Next()) {
536           BB.Add(aComp, BLOit.Value());
537         }
538
539         // 5. Glue Faces
540         aShape = GEOMImpl_GlueDriver::GlueFaces(aComp, Precision::Confusion());
541       }
542
543     } else if (aType == BLOCK_MULTI_TRANSFORM_1D ||
544                aType == BLOCK_MULTI_TRANSFORM_2D) {
545
546       TopoDS_Shape aMulti;
547       GEOMImpl_IBlockTrsf aCI (aFunction);
548       Handle(GEOM_Function) aRefShape = aCI.GetOriginal();
549       TopoDS_Shape aBlockIni = aRefShape->GetValue();
550       if (aBlockIni.IsNull()) {
551         Standard_NullObject::Raise("Null Block");
552       }
553
554       // Copy block to avoid problems (PAL6706)
555       TColStd_IndexedDataMapOfTransientTransient aMap;
556       TopoDS_Shape aBlock;
557       TNaming_CopyShape::CopyTool(aBlockIni, aMap, aBlock);
558
559       // Block tolerance in vertices
560       Standard_Real aTol = prec;
561       TopExp_Explorer expV (aBlock, TopAbs_VERTEX);
562       TopTools_MapOfShape mapShape;
563       for (; expV.More(); expV.Next()) {
564         if (mapShape.Add(expV.Current())) {
565           TopoDS_Vertex aV = TopoDS::Vertex(expV.Current());
566           aTol = Max(BRep_Tool::Tolerance(aV), aTol);
567         }
568       }
569
570       if (aType == BLOCK_MULTI_TRANSFORM_1D) {
571         // Retrieve a faces by Ids
572         Standard_Integer aFace1Id = aCI.GetFace1U();
573         Standard_Integer aFace2Id = aCI.GetFace2U();
574         TopoDS_Shape aFace1, aFace2;
575         if (!GEOMImpl_ILocalOperations::GetSubShape(aBlock, aFace1Id, aFace1)) {
576           Standard_NullObject::Raise("Can not retrieve a sub-shape with given Id");
577         }
578         if (aFace1.ShapeType() != TopAbs_FACE) {
579           Standard_TypeMismatch::Raise("Sub-shape with given Id is not a face");
580         }
581
582         if (aFace2Id > 0) {
583           if (!GEOMImpl_ILocalOperations::GetSubShape(aBlock, aFace2Id, aFace2)) {
584             Standard_NullObject::Raise("Can not retrieve a sub-shape with given Id");
585           }
586           if (aFace2.ShapeType() != TopAbs_FACE) {
587             Standard_TypeMismatch::Raise("Sub-shape with given Id is not a face");
588           }
589         }
590
591         Standard_Integer aNbIter = aCI.GetNbIterU();
592
593         MultiTransformate1D(aBlock, aFace1, aFace2, aNbIter, aMulti);
594
595       } else { // aType == BLOCK_MULTI_TRANSFORM_2D
596         // Retrieve a faces by Ids
597         Standard_Integer aFace1UId = aCI.GetFace1U();
598         Standard_Integer aFace2UId = aCI.GetFace2U();
599         Standard_Integer aFace1VId = aCI.GetFace1V();
600         Standard_Integer aFace2VId = aCI.GetFace2V();
601
602         TopoDS_Shape aFace1U, aFace2U, aFace1V, aFace2V;
603         if (!GEOMImpl_ILocalOperations::GetSubShape(aBlock, aFace1UId, aFace1U) ||
604             !GEOMImpl_ILocalOperations::GetSubShape(aBlock, aFace1VId, aFace1V)) {
605           Standard_NullObject::Raise("Can not retrieve a sub-shape with given Id");
606         }
607
608         if (aFace1U.ShapeType() != TopAbs_FACE ||
609             aFace1V.ShapeType() != TopAbs_FACE) {
610           Standard_TypeMismatch::Raise("Sub-shape with given Id is not a face");
611         }
612
613         if (aFace2UId > 0) {
614           if (!GEOMImpl_ILocalOperations::GetSubShape(aBlock, aFace2UId, aFace2U)) {
615             Standard_NullObject::Raise("Can not retrieve a sub-shape with given Id");
616           }
617
618           if (aFace2U.ShapeType() != TopAbs_FACE) {
619             Standard_TypeMismatch::Raise("Sub-shape with given Id is not a face");
620           }
621         }
622
623         if (aFace2VId > 0) {
624           if (!GEOMImpl_ILocalOperations::GetSubShape(aBlock, aFace2VId, aFace2V)) {
625             Standard_NullObject::Raise("Can not retrieve a sub-shape with given Id");
626           }
627
628           if (aFace2V.ShapeType() != TopAbs_FACE) {
629             Standard_TypeMismatch::Raise("Sub-shape with given Id is not a face");
630           }
631         }
632
633         Standard_Integer aNbIterU = aCI.GetNbIterU();
634         Standard_Integer aNbIterV = aCI.GetNbIterV();
635
636         MultiTransformate2D(aBlock,
637                             aFace1U, aFace2U, aNbIterU,
638                             aFace1V, aFace2V, aNbIterV, aMulti);
639       }
640
641       if (aMulti.IsNull()) {
642         StdFail_NotDone::Raise("Multi-transformation failed");
643       }
644
645       // Glue faces of the multi-block
646       aShape = GEOMImpl_GlueDriver::GlueFaces(aMulti, aTol);
647
648     } else { // unknown function type
649       return 0;
650     }
651   }
652
653   if (aShape.IsNull()) return 0;
654
655   aFunction->SetValue(aShape);
656
657   log.SetTouched(Label());
658
659   return 1;
660 }
661
662 //=======================================================================
663 //function :  MultiTransformate1D
664 //purpose  :
665 //=======================================================================
666 void GEOMImpl_BlockDriver::MultiTransformate1D (const TopoDS_Shape&    theBlock,
667                                                 const TopoDS_Shape&    theFace1,
668                                                 const TopoDS_Shape&    theFace2,
669                                                 const Standard_Integer theNbIter,
670                                                 TopoDS_Shape&          theResult) const
671 {
672   // Construct Tool, where <theFace1> will be the first face,
673   // and a face, opposite to <theFace1>, will be the second face
674   GEOMImpl_Block6Explorer aBlockTool;
675   aBlockTool.InitByBlockAndFace(theBlock, theFace1);
676
677   // Find IDs of the faces
678   Standard_Integer dir_face1 = 1, dir_face2 = 2;
679   if (!theFace2.IsNull()) {
680     dir_face2 = aBlockTool.GetFaceID(theFace2);
681   }
682
683   // Find three pairs of points
684   Standard_Integer v11_id = 0, v12_id = 0, v13_id = 0; // vertices of the first face
685   Standard_Integer v21_id = 0, v22_id = 0, v23_id = 0; // vertices of the second face
686
687   if (dir_face2 == 2) { // <theFace2> is opposite to <theFace1>
688
689     // We will take vertices with equal local numbers on the faces,
690     // as the Block6Explorer gives equal local numbers
691     // to the linked vertices on the opposite faces,
692     // i.e. v1* is linked with the v2* by an edge:
693
694     //          _________
695     //        /|v23     /|
696     //       / |       / |    dir_face1 - bottom
697     //      /  |      /  |
698     //     /________ /   |    dir_face2 - top
699     //    |v21 |    |v22 |
700     //    |    |____|____|
701     //    |   / v13 |   /
702     //    |  /      |  /
703     //    | /       | /
704     //    |/________|/
705     //     v11       v12
706
707     v11_id = aBlockTool.GetVertexID(dir_face1, 1);
708     v12_id = aBlockTool.GetVertexID(dir_face1, 2);
709     v13_id = aBlockTool.GetVertexID(dir_face1, 4);
710
711     v21_id = aBlockTool.GetVertexID(dir_face2, 1);
712     v22_id = aBlockTool.GetVertexID(dir_face2, 2);
713     v23_id = aBlockTool.GetVertexID(dir_face2, 4);
714
715   } else {
716
717     //          _________
718     //        /|        /|
719     //       / |       / |    dir_face1 - bottom
720     //      /  |      /  |
721     //     /________ /   |    dir_face2 - right (for example)
722     //    |    |    |v23 |
723     //    |    |____|____|
724     //    |   /     |   /v12 = v22 (common_vertex2)
725     //    |  /      |  /
726     //    | /       | /
727     //    |/________|/
728     //     v13       v11 = v21 (common_vertex1)
729
730     Standard_Integer common_edge_id = aBlockTool.FindCommonEdgeID(dir_face1, dir_face2);
731     Standard_Integer common_vertex1 = aBlockTool.GetVertexOnEdgeID(common_edge_id, 1);
732     Standard_Integer common_vertex2 = aBlockTool.GetVertexOnEdgeID(common_edge_id, 2);
733
734     Standard_Integer not_common_v1 = 0;
735     Standard_Integer vid = 1;
736     Standard_Boolean isFound = Standard_False;
737     while (!isFound && vid <= 4) {
738       not_common_v1 = aBlockTool.GetVertexID(dir_face1, vid);
739       isFound = (not_common_v1 != common_vertex2 &&
740                  aBlockTool.FindEdgeID(not_common_v1, common_vertex1) != 0);
741       vid++;
742     }
743
744     Standard_Integer not_common_v2 = 0;
745     vid = 1;
746     isFound = Standard_False;
747     while (!isFound && vid <= 4) {
748       not_common_v2 = aBlockTool.GetVertexID(dir_face2, vid);
749       isFound = (not_common_v2 != common_vertex2 &&
750                  aBlockTool.FindEdgeID(not_common_v2, common_vertex1) != 0);
751       vid++;
752     }
753
754     v11_id = common_vertex1;
755     v12_id = common_vertex2;
756     v13_id = not_common_v1;
757
758     v21_id = common_vertex1;
759     v22_id = common_vertex2;
760     v23_id = not_common_v2;
761   }
762
763   // Construct a transformation operator
764   TopoDS_Vertex V11 = TopoDS::Vertex(aBlockTool.GetVertex(v11_id));
765   TopoDS_Vertex V12 = TopoDS::Vertex(aBlockTool.GetVertex(v12_id));
766   TopoDS_Vertex V13 = TopoDS::Vertex(aBlockTool.GetVertex(v13_id));
767
768   TopoDS_Vertex V21 = TopoDS::Vertex(aBlockTool.GetVertex(v21_id));
769   TopoDS_Vertex V22 = TopoDS::Vertex(aBlockTool.GetVertex(v22_id));
770   TopoDS_Vertex V23 = TopoDS::Vertex(aBlockTool.GetVertex(v23_id));
771
772   // Axes of the first direction face
773   gp_Pnt P1 = BRep_Tool::Pnt(V11);
774   gp_Vec VecN1 (P1, BRep_Tool::Pnt(V12));
775   gp_Vec VecX1 (P1, BRep_Tool::Pnt(V13));
776   gp_Ax3 Ax1 (P1, VecN1, VecX1);
777
778   // Axes of the second direction face
779   gp_Pnt P2 = BRep_Tool::Pnt(V21);
780   gp_Vec VecN2 (P2, BRep_Tool::Pnt(V22));
781   gp_Vec VecX2 (P2, BRep_Tool::Pnt(V23));
782   gp_Ax3 Ax2 (P2, VecN2, VecX2);
783
784   gp_Trsf aTrsf;
785   aTrsf.SetDisplacement(Ax1, Ax2);
786
787   // Check, that <theFace2> is similar to <theFace1>.
788   // Actually, we need only to check right position of one
789   // vertex, not involved into the transformation construction.
790   if (!aBlockTool.IsSimilarFaces(dir_face1, dir_face2, aTrsf)) {
791     Standard_ConstructionError::Raise("The direction faces are not similar");
792   }
793
794   // Perform multi-transformation
795   TopoDS_Compound aCompound;
796   BRep_Builder B;
797   B.MakeCompound(aCompound);
798
799   TopoDS_Shape aPrevShape = theBlock;
800   for (Standard_Integer i = 0; i < theNbIter; i++) {
801     B.Add(aCompound, aPrevShape);
802     BRepBuilderAPI_Transform aTransformation (aPrevShape, aTrsf, Standard_False);
803     aPrevShape = aTransformation.Shape();
804   }
805   theResult = aCompound;
806 }
807
808 //=======================================================================
809 //function :  MultiTransformate2D
810 //purpose  :
811 //=======================================================================
812 void GEOMImpl_BlockDriver::MultiTransformate2D (const TopoDS_Shape&    theBlock,
813                                                 const TopoDS_Shape&    theFace1U,
814                                                 const TopoDS_Shape&    theFace2U,
815                                                 const Standard_Integer theNbIterU,
816                                                 const TopoDS_Shape&    theFace1V,
817                                                 const TopoDS_Shape&    theFace2V,
818                                                 const Standard_Integer theNbIterV,
819                                                 TopoDS_Shape&          theResult) const
820 {
821   // Construct Tool, where <theFace1U> will be the first face,
822   // and a face, opposite to <theFace1U>, will be the second face
823   GEOMImpl_Block6Explorer aBlockTool;
824   aBlockTool.InitByBlockAndFace(theBlock, theFace1U);
825
826   gp_Trsf aTrsfU, aTrsfV;
827   gp_Ax3 Ax1V, Ax2V;
828   for (Standard_Integer uv = 1; uv <= 2; uv++) {
829     // U transformation
830     TopoDS_Shape theFace1 = theFace1U;
831     TopoDS_Shape theFace2 = theFace2U;
832     if (uv == 2) {
833       // V transformation
834       theFace1 = theFace1V;
835       theFace2 = theFace2V;
836     }
837
838     // Find IDs of the faces
839     Standard_Integer dir_face1 = aBlockTool.GetFaceID(theFace1);
840     Standard_Integer dir_face2 = 0;
841     Standard_Integer opp_face1 = aBlockTool.GetOppositeFaceID(dir_face1);
842     if (theFace2.IsNull()) {
843       dir_face2 = opp_face1;
844     } else {
845       dir_face2 = aBlockTool.GetFaceID(theFace2);
846     }
847
848     // Find three pairs of points
849     Standard_Integer v11_id = 0, v12_id = 0, v13_id = 0; // vertices of the first face
850     Standard_Integer v21_id = 0, v22_id = 0, v23_id = 0; // vertices of the second face
851
852     if (dir_face2 == opp_face1) { // <theFace2> is opposite to <theFace1>
853
854       // We will take vertices with equal local numbers on the faces,
855       // as the Block6Explorer gives equal local numbers
856       // to the linked vertices on the opposite faces,
857       // i.e. v1* is linked with the v2* by an edge:
858
859       v11_id = aBlockTool.GetVertexID(dir_face1, 1);
860       v12_id = aBlockTool.GetVertexID(dir_face1, 2);
861       v13_id = aBlockTool.GetVertexID(dir_face1, 4);
862
863       v21_id = aBlockTool.GetVertexID(dir_face2, 1);
864       v22_id = aBlockTool.GetVertexID(dir_face2, 2);
865       v23_id = aBlockTool.GetVertexID(dir_face2, 4);
866
867     } else {
868
869       Standard_Integer common_edge_id = aBlockTool.FindCommonEdgeID(dir_face1, dir_face2);
870       Standard_Integer common_vertex1 = aBlockTool.GetVertexOnEdgeID(common_edge_id, 1);
871       Standard_Integer common_vertex2 = aBlockTool.GetVertexOnEdgeID(common_edge_id, 2);
872
873       Standard_Integer not_common_v1 = 0;
874       Standard_Integer vid = 1;
875       Standard_Boolean isFound = Standard_False;
876       while (!isFound && vid <= 4) {
877         not_common_v1 = aBlockTool.GetVertexID(dir_face1, vid);
878         isFound = (not_common_v1 != common_vertex2 &&
879                    aBlockTool.FindEdgeID(not_common_v1, common_vertex1) != 0);
880         vid++;
881       }
882
883       Standard_Integer not_common_v2 = 0;
884       vid = 1;
885       isFound = Standard_False;
886       while (!isFound && vid <= 4) {
887         not_common_v2 = aBlockTool.GetVertexID(dir_face2, vid);
888         isFound = (not_common_v2 != common_vertex2 &&
889                    aBlockTool.FindEdgeID(not_common_v2, common_vertex1) != 0);
890         vid++;
891       }
892
893       v11_id = common_vertex1;
894       v12_id = common_vertex2;
895       v13_id = not_common_v1;
896
897       v21_id = common_vertex1;
898       v22_id = common_vertex2;
899       v23_id = not_common_v2;
900     }
901
902     // Construct a transformation operator
903     TopoDS_Vertex V11 = TopoDS::Vertex(aBlockTool.GetVertex(v11_id));
904     TopoDS_Vertex V12 = TopoDS::Vertex(aBlockTool.GetVertex(v12_id));
905     TopoDS_Vertex V13 = TopoDS::Vertex(aBlockTool.GetVertex(v13_id));
906
907     TopoDS_Vertex V21 = TopoDS::Vertex(aBlockTool.GetVertex(v21_id));
908     TopoDS_Vertex V22 = TopoDS::Vertex(aBlockTool.GetVertex(v22_id));
909     TopoDS_Vertex V23 = TopoDS::Vertex(aBlockTool.GetVertex(v23_id));
910
911     // Axes of the first direction face
912     gp_Pnt P1 = BRep_Tool::Pnt(V11);
913     gp_Vec VecN1 (P1, BRep_Tool::Pnt(V12));
914     gp_Vec VecX1 (P1, BRep_Tool::Pnt(V13));
915     gp_Ax3 Ax1 (P1, VecN1, VecX1);
916
917     // Axes of the second direction face
918     gp_Pnt P2 = BRep_Tool::Pnt(V21);
919     gp_Vec VecN2 (P2, BRep_Tool::Pnt(V22));
920     gp_Vec VecX2 (P2, BRep_Tool::Pnt(V23));
921     gp_Ax3 Ax2 (P2, VecN2, VecX2);
922
923     gp_Trsf aTrsf;
924     aTrsf.SetDisplacement(Ax1, Ax2);
925     if (uv == 1) {
926       aTrsfU = aTrsf;
927     } else {
928       aTrsfV = aTrsf;
929       Ax1V = Ax1;
930       Ax2V = Ax2;
931     }
932
933     // Check, that <theFace2> is similar to <theFace1>.
934     // Actually, we need only to check right position of one
935     // vertex, not involved into the transformation construction.
936     if (!aBlockTool.IsSimilarFaces(dir_face1, dir_face2, aTrsf)) {
937       Standard_ConstructionError::Raise("The direction faces are not similar");
938     }
939   }
940
941   // Perform multi-transformation
942   TopoDS_Compound aCompound;
943   BRep_Builder B;
944   B.MakeCompound(aCompound);
945
946   TopoDS_Shape aPrevShapeU = theBlock;
947   for (int i = 0; i < theNbIterU; i++) {
948     TopoDS_Shape aPrevShapeV = aPrevShapeU;
949     for (int j = 0; j < theNbIterV; j++) {
950       B.Add(aCompound, aPrevShapeV);
951       BRepBuilderAPI_Transform aTransformationV (aPrevShapeV, aTrsfV, Standard_False);
952       aPrevShapeV = aTransformationV.Shape();
953     }
954     BRepBuilderAPI_Transform aTransformationU (aPrevShapeU, aTrsfU, Standard_False);
955     aPrevShapeU = aTransformationU.Shape();
956     // Correction of the second transformation according to the first transformation
957     Ax1V.Transform(aTrsfU);
958     Ax2V.Transform(aTrsfU);
959     aTrsfV.SetDisplacement(Ax1V, Ax2V);
960     // Correction done
961   }
962   theResult = aCompound;
963 }
964
965 //=======================================================================
966 //function :  GEOMImpl_BlockDriver_Type_
967 //purpose  :
968 //=======================================================================
969 Standard_EXPORT Handle_Standard_Type& GEOMImpl_BlockDriver_Type_()
970 {
971
972   static Handle_Standard_Type aType1 = STANDARD_TYPE(TFunction_Driver);
973   if ( aType1.IsNull()) aType1 = STANDARD_TYPE(TFunction_Driver);
974   static Handle_Standard_Type aType2 = STANDARD_TYPE(MMgt_TShared);
975   if ( aType2.IsNull()) aType2 = STANDARD_TYPE(MMgt_TShared);
976   static Handle_Standard_Type aType3 = STANDARD_TYPE(Standard_Transient);
977   if ( aType3.IsNull()) aType3 = STANDARD_TYPE(Standard_Transient);
978
979
980   static Handle_Standard_Transient _Ancestors[]= {aType1,aType2,aType3,NULL};
981   static Handle_Standard_Type _aType = new Standard_Type("GEOMImpl_BlockDriver",
982                                                          sizeof(GEOMImpl_BlockDriver),
983                                                          1,
984                                                          (Standard_Address)_Ancestors,
985                                                          (Standard_Address)NULL);
986
987   return _aType;
988 }
989
990 //=======================================================================
991 //function : DownCast
992 //purpose  :
993 //=======================================================================
994 const Handle(GEOMImpl_BlockDriver) Handle(GEOMImpl_BlockDriver)::DownCast(const Handle(Standard_Transient)& AnObject)
995 {
996   Handle(GEOMImpl_BlockDriver) _anOtherObject;
997
998   if (!AnObject.IsNull()) {
999      if (AnObject->IsKind(STANDARD_TYPE(GEOMImpl_BlockDriver))) {
1000        _anOtherObject = Handle(GEOMImpl_BlockDriver)((Handle(GEOMImpl_BlockDriver)&)AnObject);
1001      }
1002   }
1003
1004   return _anOtherObject ;
1005 }