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