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