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