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