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