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