Salome HOME
d5a336321773bf7661a76731c8fe8c8c265553f4
[modules/geom.git] / src / AdvancedEngine / AdvancedEngine_IOperations.cxx
1 // Copyright (C) 2007-2023  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19 //  File   : AdvancedEngine_IOperations.cxx
20 //  Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com)
21
22 #include "AdvancedEngine_IOperations.hxx"
23 #include "AdvancedEngine_PipeTShapeDriver.hxx"
24 #include "AdvancedEngine_IPipeTShape.hxx"
25 #include "AdvancedEngine_DividedDiskDriver.hxx"
26 #include "AdvancedEngine_IDividedDisk.hxx"
27 #include "AdvancedEngine_SmoothingSurfaceDriver.hxx"
28 #include "AdvancedEngine_ISmoothingSurface.hxx"
29
30 #include <utilities.h>
31 #include <OpUtil.hxx>
32 #include <Utils_ExceptHandlers.hxx>
33
34 #include <GEOM_Function.hxx>
35 #include <GEOM_PythonDump.hxx>
36 #include <GEOMUtils.hxx>
37 #include <GEOMAlgo_ClsfSurf.hxx>
38 #include <GEOMAlgo_FinderShapeOn2.hxx>
39 #include <GEOMAlgo_Splitter.hxx>
40
41 #include <GEOMImpl_Gen.hxx>
42 #include <GEOMImpl_Types.hxx>
43
44 #include <GEOMImpl_IBasicOperations.hxx>
45 #include <GEOMImpl_IBooleanOperations.hxx>
46 #include <GEOMImpl_IShapesOperations.hxx>
47 #include <GEOMImpl_ITransformOperations.hxx>
48 #include <GEOMImpl_IBlocksOperations.hxx>
49 #include <GEOMImpl_I3DPrimOperations.hxx>
50 #include <GEOMImpl_ILocalOperations.hxx>
51 #include <GEOMImpl_IHealingOperations.hxx>
52 #include <GEOMImpl_IGroupOperations.hxx>
53 #include <GEOMImpl_GlueDriver.hxx>
54
55 #include <TDF_Tool.hxx>
56 #include <TFunction_DriverTable.hxx>
57 #include <TFunction_Driver.hxx>
58 #include <TNaming_CopyShape.hxx>
59
60 #include <TopExp.hxx>
61 #include <TopExp_Explorer.hxx>
62 #include <TopoDS.hxx>
63 #include <TopoDS_Vertex.hxx>
64 #include <TopTools_IndexedMapOfShape.hxx>
65 #include <TopTools_ListIteratorOfListOfShape.hxx>
66 #include <TColStd_IndexedDataMapOfTransientTransient.hxx>
67
68 #include <BRep_Builder.hxx>
69 #include <BRep_Tool.hxx>
70
71 #include <BRepAdaptor_Surface.hxx>
72 #include <BRepAlgoAPI_Cut.hxx>
73 #include <BRepAlgoAPI_Fuse.hxx>
74 #include <BRepBuilderAPI_MakeFace.hxx>
75 #include <BRepBuilderAPI_MakeVertex.hxx>
76 #include <BRepBuilderAPI_Transform.hxx>
77 #include <BRepPrimAPI_MakeCone.hxx>
78 #include <BRepPrimAPI_MakeCylinder.hxx>
79
80 #include <gp_Ax3.hxx>
81 #include <gp_Pln.hxx>
82 #include <gp_Pnt.hxx>
83 #include <gp_Vec.hxx>
84 #include <GC_MakeConicalSurface.hxx>
85 #include <Geom_CylindricalSurface.hxx>
86
87 #include <ShapeAnalysis_Edge.hxx>
88
89 #include <cmath>
90
91 #include "AdvancedEngine_Types.hxx"
92
93 #include <Standard_Stream.hxx>
94 #include <Standard_Failure.hxx>
95 #include <StdFail_NotDone.hxx>
96 #include <Standard_ErrorHandler.hxx> // CAREFUL ! position of this file is critic : see Lucien PIGNOLONI / OCC
97
98 #define HALF_LENGTH_MAIN_PIPE     "Main pipe half length" //"Tuyau principal - demi longueur"
99 #define HALF_LENGTH_INCIDENT_PIPE "Incident pipe half length" //"Tuyau incident - demi longueur"
100 #define CIRCULAR_QUARTER_PIPE     "Circular quarter of pipe" //"Circulaire - quart de tuyau"
101 #define THICKNESS                 "Thickness" //"Epaisseur"
102 #define FLANGE                    "Flange" // "Collerette"
103 #define CHAMFER_OR_FILLET         "Chamfer or fillet" //"Chanfrein ou Raccord"
104 #define JUNCTION_FACE_1           "Junction 1" //"Face de jonction 1"
105 #define JUNCTION_FACE_2           "Junction 2" //"Face de jonction 2"
106 #define JUNCTION_FACE_3           "Junction 3" //"Face de jonction 3"
107
108 #define FIND_GROUPS_BY_POINTS 1
109
110 // Undefine below macro to enable workaround about fillet problem in MakePipeTShapeFillet
111 // VSR 30/12/2014: macro enabled
112 #define FILLET_FIX_TOLERANCE
113
114 //=============================================================================
115 /*!
116  *  Constructor
117  */
118 //=============================================================================
119 AdvancedEngine_IOperations::AdvancedEngine_IOperations(GEOM_Engine* theEngine) :
120   GEOM_IOperations(theEngine)
121 {
122   MESSAGE("AdvancedEngine_IOperations::AdvancedEngine_IOperations");
123   myBasicOperations     = new GEOMImpl_IBasicOperations(GetEngine());
124   myBooleanOperations   = new GEOMImpl_IBooleanOperations(GetEngine());
125   myShapesOperations    = new GEOMImpl_IShapesOperations(GetEngine());
126   myTransformOperations = new GEOMImpl_ITransformOperations(GetEngine());
127   myBlocksOperations    = new GEOMImpl_IBlocksOperations(GetEngine());
128   my3DPrimOperations    = new GEOMImpl_I3DPrimOperations(GetEngine());
129   myLocalOperations     = new GEOMImpl_ILocalOperations(GetEngine());
130   myHealingOperations   = new GEOMImpl_IHealingOperations(GetEngine());
131   myGroupOperations     = new GEOMImpl_IGroupOperations(GetEngine());
132 }
133
134 //=============================================================================
135 /*!
136  *  Destructor
137  */
138 //=============================================================================
139 AdvancedEngine_IOperations::~AdvancedEngine_IOperations()
140 {
141   MESSAGE("AdvancedEngine_IOperations::~AdvancedEngine_IOperations");
142   delete myBasicOperations;
143   delete myBooleanOperations;
144   delete myShapesOperations;
145   delete myTransformOperations;
146   delete myBlocksOperations;
147   delete my3DPrimOperations;
148   delete myLocalOperations;
149   delete myHealingOperations;
150   delete myGroupOperations;
151 }
152
153 //=============================================================================
154 /*!
155  *  SetPosition
156  */
157 //=============================================================================
158 gp_Trsf AdvancedEngine_IOperations::GetPositionTrsf(double theL1, double theL2,
159                                                     Handle(GEOM_Object) theP1,
160                                                     Handle(GEOM_Object) theP2,
161                                                     Handle(GEOM_Object) theP3)
162 {
163   // Old Local Coordinates System oldLCS
164   gp_Pnt P0(0, 0, 0);
165   gp_Pnt P1(-theL1, 0, 0);
166   gp_Pnt P2(theL1, 0, 0);
167   gp_Pnt P3(0, 0, theL2);
168
169   gp_Dir oldX(gp_Vec(P1, P2));
170   gp_Dir oldZ(gp_Vec(P0, P3));
171   gp_Ax3 oldLCS(P0, oldZ, oldX);
172
173   // New Local Coordinates System newLCS
174   double LocX, LocY, LocZ;
175   gp_Pnt newP1 = BRep_Tool::Pnt(TopoDS::Vertex(theP1->GetValue()));
176   gp_Pnt newP2 = BRep_Tool::Pnt(TopoDS::Vertex(theP2->GetValue()));
177   gp_Pnt newP3 = BRep_Tool::Pnt(TopoDS::Vertex(theP3->GetValue()));
178   LocX = (newP1.X() + newP2.X()) / 2.;
179   LocY = (newP1.Y() + newP2.Y()) / 2.;
180   LocZ = (newP1.Z() + newP2.Z()) / 2.;
181   gp_Pnt newO(LocX, LocY, LocZ);
182
183   gp_Dir newX(gp_Vec(newP1, newP2)); // P1P2 Vector
184   gp_Dir newZ(gp_Vec(newO, newP3)); // OP3 Vector
185   gp_Ax3 newLCS = gp_Ax3(newO, newZ, newX);
186
187   gp_Trsf aTrsf;
188   aTrsf.SetDisplacement(oldLCS, newLCS);
189
190   return aTrsf;
191 }
192
193 //=============================================================================
194 /*!
195  *  CheckCompatiblePosition
196  *
197  */
198 //=============================================================================
199 bool AdvancedEngine_IOperations::CheckCompatiblePosition(double& theL1, double& theL2,
200                                                          Handle(GEOM_Object) theP1,
201                                                          Handle(GEOM_Object) theP2,
202                                                          Handle(GEOM_Object) theP3,
203                                                          double theTolerance)
204 {
205   SetErrorCode(KO);
206   gp_Pnt P1 = BRep_Tool::Pnt(TopoDS::Vertex(theP1->GetValue()));
207   gp_Pnt P2 = BRep_Tool::Pnt(TopoDS::Vertex(theP2->GetValue()));
208   gp_Pnt P3 = BRep_Tool::Pnt(TopoDS::Vertex(theP3->GetValue()));
209
210   double d12 = P1.Distance(P2);
211   double d13 = P1.Distance(P3);
212   double d23 = P2.Distance(P3);
213   //    double d2 = newO.Distance(P3);
214
215   if (Abs(d12) <= Precision::Confusion()) {
216     SetErrorCode("Junctions points P1 and P2 are identical");
217     return false;
218   }
219   if (Abs(d13) <= Precision::Confusion()) {
220     SetErrorCode("Junctions points P1 and P3 are identical");
221     return false;
222   }
223   if (Abs(d23) <= Precision::Confusion()) {
224     SetErrorCode("Junctions points P2 and P3 are identical");
225     return false;
226   }
227
228
229   double newL1 = 0.5 * d12;
230   double newL2 = sqrt(pow(d13,2)-pow(newL1,2));
231   //
232   // theL1*(1-theTolerance) <= newL1 <= theL1*(1+theTolerance)
233   //
234   if (fabs(newL1 - theL1) > Precision::Approximation()) {
235     if ( (newL1 * (1 - theTolerance) -theL1 <= Precision::Approximation()) &&
236          (newL1 * (1 + theTolerance) -theL1 >= Precision::Approximation()) ) {
237       //            std::cerr << "theL1 = newL1" << std::endl;
238       theL1 = newL1;
239     } else {
240       theL1 = -1;
241       SetErrorCode("Dimension for main pipe (L1) is incompatible with new position");
242       return false;
243     }
244   }
245
246   //
247   // theL2*(1-theTolerance) <= newL2  <= theL2*(1+theTolerance)
248   //
249   if (fabs(newL2 - theL2) > Precision::Approximation()) {
250     if ( (newL2 * (1 - theTolerance) -theL2 <= Precision::Approximation()) &&
251          (newL2 * (1 + theTolerance) -theL2 >= Precision::Approximation()) ) {
252       theL2 = newL2;
253     } else {
254       theL2 = -1;
255       SetErrorCode("Dimension for incident pipe (L2) is incompatible with new position");
256       return false;
257     }
258   }
259
260   SetErrorCode(OK);
261   return true;
262
263 }
264
265 //=============================================================================
266 /*!
267  *  Generate the propagation groups of a Pipe T-Shape used for hexa mesh
268  */
269 //=============================================================================
270 bool AdvancedEngine_IOperations::MakeGroups(Handle(GEOM_Object) theShape, int shapeType,
271                                             double theR1, double theW1, double theL1,
272                                             double theR2, double theW2, double theL2,
273                                             double theH, double theW, double theRF,
274                                             Handle(TColStd_HSequenceOfTransient) theSeq,
275                                             gp_Trsf aTrsf)
276 {
277   SetErrorCode(KO);
278
279   if (theShape.IsNull()) return false;
280
281   TopoDS_Shape aShape = theShape->GetValue();
282   if (aShape.IsNull()) {
283     SetErrorCode("Shape is not defined");
284     return false;
285   }
286
287 //   int expectedGroups = 0;
288 //   if (shapeType == TSHAPE_BASIC)
289 //     if (Abs(theR2+theW2-theR1-theW1) <= Precision::Approximation())
290 //       expectedGroups = 10;
291 //     else
292 //       expectedGroups = 11;
293 //   else if (shapeType == TSHAPE_CHAMFER || shapeType == TSHAPE_FILLET)
294 //     expectedGroups = 12;
295
296   double aR1Ext = theR1 + theW1;
297   double aR2Ext = theR2 + theW2;
298
299   /////////////////////////
300   //// Groups of Faces ////
301   /////////////////////////
302
303   //
304   // Comment the following lines when GetInPlace bug is solved
305   // == BEGIN
306   // Workaround of GetInPlace bug
307   // Create a bounding box that fits the shape
308   Handle(GEOM_Object) aBox = my3DPrimOperations->MakeBoxDXDYDZ(2*theL1, 2*aR1Ext, aR1Ext+theL2);
309   aBox->GetLastFunction()->SetDescription("");
310   myTransformOperations->TranslateDXDYDZ(aBox, -theL1, -aR1Ext, -aR1Ext);
311   aBox->GetLastFunction()->SetDescription("");
312   // Apply transformation to box
313   BRepBuilderAPI_Transform aTransformationBox(aBox->GetValue(), aTrsf, Standard_False);
314   TopoDS_Shape aBoxShapeTrsf = aTransformationBox.Shape();
315   aBox->GetLastFunction()->SetValue(aBoxShapeTrsf);
316
317   // Get the shell of the box
318   Handle(GEOM_Object) aShell = Handle(GEOM_Object)::DownCast
319     (myShapesOperations->MakeExplode(aBox, TopAbs_SHELL, true)->Value(1));
320   aBox->GetLastFunction()->SetDescription("");
321   aShell->GetLastFunction()->SetDescription("");
322   // Get the common shapes between shell and shape
323   Handle(GEOM_Object) aCommonCompound = myBooleanOperations->MakeBoolean
324                             (theShape, aShell, 1, Standard_False); // MakeCommon
325   if (aCommonCompound.IsNull()) {
326     SetErrorCode(myBooleanOperations->GetErrorCode());
327     return false;
328   }
329   aCommonCompound->GetLastFunction()->SetDescription("");
330   // Explode the faces of common shapes => 3 faces
331   Handle(TColStd_HSequenceOfTransient) aCommonFaces =
332     myShapesOperations->MakeExplode(aCommonCompound, TopAbs_FACE, true);
333   aCommonCompound->GetLastFunction()->SetDescription("");
334   std::list<Handle(GEOM_Object)> aCompoundOfFacesList;
335
336   for (int i=0 ; i<= aCommonFaces->Length()-4 ; i+=4) {
337     std::list<Handle(GEOM_Object)> aFacesList;
338     for (int j = 1 ; j <= 4 ; j++) {
339       Handle(GEOM_Object) aFace = Handle(GEOM_Object)::DownCast(aCommonFaces->Value(i+j)); // Junction faces
340       if (!aFace.IsNull()) {
341         aFace->GetLastFunction()->SetDescription("");
342         aFacesList.push_back(aFace);
343       }
344     }
345     Handle(GEOM_Object) aCompoundOfFaces = myShapesOperations->MakeCompound(aFacesList);
346     if (!aCompoundOfFaces.IsNull()) {
347       aCompoundOfFaces->GetLastFunction()->SetDescription("");
348       aCompoundOfFacesList.push_back(aCompoundOfFaces);
349     }
350   }
351
352   if (aCompoundOfFacesList.size() == 3) {
353     Handle(GEOM_Object) aPln1 = aCompoundOfFacesList.front();
354     aCompoundOfFacesList.pop_front();
355     Handle(GEOM_Object) aPln2 = aCompoundOfFacesList.front();
356     aCompoundOfFacesList.pop_front();
357     Handle(GEOM_Object) aPln3 = aCompoundOfFacesList.front();
358     aCompoundOfFacesList.pop_front();
359     // == END
360     //
361
362
363     //     Uncomment the following lines when GetInPlace bug is solved
364     //     == BEGIN
365 //     Handle(GEOM_Object) aP1 = myBasicOperations->MakePointXYZ(-theL1, 0, 0);
366 //     Handle(GEOM_Object) aP2 = myBasicOperations->MakePointXYZ(-0, 0, theL2);
367 //     Handle(GEOM_Object) aP3 = myBasicOperations->MakePointXYZ(theL1, 0, 0);
368 //     aP1->GetLastFunction()->SetDescription("");
369 //     aP2->GetLastFunction()->SetDescription("");
370 //     aP3->GetLastFunction()->SetDescription("");
371 //     Handle(GEOM_Object) aV1 = myBasicOperations->MakeVectorDXDYDZ(-1, 0, 0);
372 //     Handle(GEOM_Object) aV2 = myBasicOperations->MakeVectorDXDYDZ(0, 0, 1);
373 //     Handle(GEOM_Object) aV3 = myBasicOperations->MakeVectorDXDYDZ(1, 0, 0);
374 //     aV1->GetLastFunction()->SetDescription("");
375 //     aV2->GetLastFunction()->SetDescription("");
376 //     aV3->GetLastFunction()->SetDescription("");
377 //     Handle(GEOM_Object) aPln1 = myBasicOperations->MakePlanePntVec(aP1, aV1, 2*(aR1Ext+theL2));
378 //     Handle(GEOM_Object) aPln2 = myBasicOperations->MakePlanePntVec(aP2, aV2, 2*(aR2Ext));
379 //     Handle(GEOM_Object) aPln3 = myBasicOperations->MakePlanePntVec(aP3, aV3, 2*(aR1Ext+theL2));
380 //     aPln1->GetLastFunction()->SetDescription("");
381 //     aPln2->GetLastFunction()->SetDescription("");
382 //     aPln3->GetLastFunction()->SetDescription("");
383 //
384 //     BRepBuilderAPI_Transform aTransformation1(aPln1->GetValue(), aTrsf, Standard_False);
385 //     TopoDS_Shape aTrsf_Shape1 = aTransformation1.Shape();
386 //     aPln1->GetLastFunction()->SetValue(aTrsf_Shape1);
387 //     BRepBuilderAPI_Transform aTransformation2(aPln2->GetValue(), aTrsf, Standard_False);
388 //     TopoDS_Shape aTrsf_Shape2 = aTransformation2.Shape();
389 //     aPln2->GetLastFunction()->SetValue(aTrsf_Shape2);
390 //     BRepBuilderAPI_Transform aTransformation3(aPln3->GetValue(), aTrsf, Standard_False);
391 //     TopoDS_Shape aTrsf_Shape3 = aTransformation3.Shape();
392 //     aPln3->GetLastFunction()->SetValue(aTrsf_Shape3);
393     //     == END
394     //
395
396     Handle(GEOM_Object) junctionFaces1 = myShapesOperations->GetInPlace(theShape, aPln1);
397     if (junctionFaces1.IsNull())
398       junctionFaces1 = myShapesOperations->GetShapesOnShapeAsCompound
399         (aPln1, theShape, TopAbs_FACE,  GEOMAlgo_ST_ONIN);
400     if (!junctionFaces1.IsNull()) {
401       junctionFaces1->GetLastFunction()->SetDescription("");
402       junctionFaces1->SetName("JUNCTION_FACE_1");
403       theSeq->Append(junctionFaces1);
404     }
405     else {
406       SetErrorCode("Junction face 1 not found");
407       //        theSeq->Append(aPln1);
408       //        return false;
409     }
410     Handle(GEOM_Object) junctionFaces2 = myShapesOperations->GetInPlace(theShape, aPln2);
411     if (junctionFaces2.IsNull())
412       junctionFaces2 = myShapesOperations->GetShapesOnShapeAsCompound
413         (aPln2, theShape, TopAbs_FACE,  GEOMAlgo_ST_ONIN);
414     if (!junctionFaces2.IsNull()) {
415       junctionFaces2->GetLastFunction()->SetDescription("");
416       junctionFaces2->SetName("JUNCTION_FACE_2");
417       theSeq->Append(junctionFaces2);
418     }
419     else {
420       SetErrorCode("Junction face 2 not found");
421       //        theSeq->Append(aPln2);
422       //        return false;
423     }
424     Handle(GEOM_Object) junctionFaces3 = myShapesOperations->GetInPlace(theShape, aPln3);
425     if (junctionFaces3.IsNull())
426       junctionFaces3 = myShapesOperations->GetShapesOnShapeAsCompound
427         (aPln3, theShape, TopAbs_FACE,  GEOMAlgo_ST_ONIN);
428     if (!junctionFaces3.IsNull()) {
429       junctionFaces3->GetLastFunction()->SetDescription("");
430       junctionFaces3->SetName("JUNCTION_FACE_3");
431       theSeq->Append(junctionFaces3);
432     }
433     else {
434       SetErrorCode("Junction face 3 not found");
435       //        theSeq->Append(aPln3);
436       //        return false;
437     }
438   // Comment the following lines when GetInPlace bug is solved
439   // == BEGIN
440   }
441   //     == END
442
443   /////////////////////////
444   //// Groups of Edges ////
445   /////////////////////////
446   // Result of propagate
447
448   Handle(GEOM_Function) aFunction = theShape->GetLastFunction();
449
450   TCollection_AsciiString theDesc = aFunction->GetDescription();
451   Handle(TColStd_HSequenceOfTransient) aSeqPropagate = myBlocksOperations->Propagate(theShape);
452   if (aSeqPropagate.IsNull() || aSeqPropagate->Length() == 0) {
453     SetErrorCode("Propagation groups not found");
454     return false;
455   }
456   Standard_Integer aNbGroups = aSeqPropagate->Length();
457   // Recover previous description to get rid of Propagate dump
458   aFunction->SetDescription(theDesc);
459
460 #ifdef FIND_GROUPS_BY_POINTS
461   // BEGIN: new groups search
462   /*
463                   W2  R2
464                 .----.-----.----.
465                e|    |  |  |    |
466                 |    |  |  |    |
467                 .    |  |  |    .
468              g / ''..|  |  |..'' \
469            f  /      '''''''      \
470       .---.--'..     |  |  |     ..'--.---.
471       |a    \   '''...........'''   /     |
472       |-------\------'  |  '------/-------.
473       |         \       |       /         |
474      c|           \     |     /           |
475       |    R1       \   |   /             |
476       |               \ | /               |
477       ._________________|_________________.
478       |       L1        |                 |
479       |                 |                 |
480       |                 |                 |
481      b|                 |                 |
482       |                 |                 |
483       |-----------------|-----------------|
484       |    W1           |                 |
485       '-----------------'-----------------'
486               d
487   */
488
489   // "Thickness" group (a)
490   gp_Pnt aPntA (-theL1, 0, theR1 + theW1/2.);
491   aPntA.Transform(aTrsf);
492   BRepBuilderAPI_MakeVertex mkVertexA (aPntA);
493   TopoDS_Vertex aVertA = TopoDS::Vertex(mkVertexA.Shape());
494   TopoDS_Shape anEdgeA = GEOMUtils::GetEdgeNearPoint(aShape, aVertA);
495
496   // "Circular quarter of pipe" group (b)
497   gp_Pnt aPntB (-theL1, -aR1Ext * sin(M_PI/4.), -aR1Ext * sin(M_PI/4.));
498   aPntB.Transform(aTrsf);
499   BRepBuilderAPI_MakeVertex mkVertexB (aPntB);
500   TopoDS_Vertex aVertB = TopoDS::Vertex(mkVertexB.Shape());
501   TopoDS_Shape anEdgeB = GEOMUtils::GetEdgeNearPoint(aShape, aVertB);
502
503   // "Circular quarter of pipe" group (c)
504   gp_Pnt aPntC (-theL1, -aR1Ext * sin(M_PI/4.), aR1Ext * sin(M_PI/4.));
505   aPntC.Transform(aTrsf);
506   BRepBuilderAPI_MakeVertex mkVertexC (aPntC);
507   TopoDS_Vertex aVertC = TopoDS::Vertex(mkVertexC.Shape());
508   TopoDS_Shape anEdgeC = GEOMUtils::GetEdgeNearPoint(aShape, aVertC);
509
510   // "Main pipe half length" group (d)
511   gp_Pnt aPntD (-theL1/2., 0, -aR1Ext);
512   aPntD.Transform(aTrsf);
513   BRepBuilderAPI_MakeVertex mkVertexD (aPntD);
514   TopoDS_Vertex aVertD = TopoDS::Vertex(mkVertexD.Shape());
515   TopoDS_Shape anEdgeD = GEOMUtils::GetEdgeNearPoint(aShape, aVertD);
516
517   // "Incident pipe half length" group (e)
518   double aTol10 = Precision::Confusion() * 10.;
519   gp_Pnt aPntE (-aR2Ext, 0, theL2 - aTol10);
520   aPntE.Transform(aTrsf);
521   BRepBuilderAPI_MakeVertex mkVertexE (aPntE);
522   TopoDS_Vertex aVertE = TopoDS::Vertex(mkVertexE.Shape());
523   TopoDS_Shape anEdgeE = GEOMUtils::GetEdgeNearPoint(aShape, aVertE);
524
525   // "Flange" group (f)
526   double aFx = - aR2Ext - aTol10;
527   if (shapeType == TSHAPE_CHAMFER)
528     aFx -= theW;
529   else if (shapeType == TSHAPE_FILLET)
530     aFx -= theRF;
531   gp_Pnt aPntF (aFx, 0, aR1Ext);
532   aPntF.Transform(aTrsf);
533   BRepBuilderAPI_MakeVertex mkVertexF (aPntF);
534   TopoDS_Vertex aVertF = TopoDS::Vertex(mkVertexF.Shape());
535   TopoDS_Shape anEdgeF = GEOMUtils::GetEdgeNearPoint(aShape, aVertF);
536
537   // "Chamfer or Fillet" group (g)
538   TopoDS_Shape anEdgeG;
539   if (shapeType == TSHAPE_CHAMFER) {
540     gp_Pnt aPntG (-aR2Ext - theW/2., 0, aR1Ext + theH/2.);
541     aPntG.Transform(aTrsf);
542     BRepBuilderAPI_MakeVertex mkVertexG (aPntG);
543     TopoDS_Vertex aVertG = TopoDS::Vertex(mkVertexG.Shape());
544     anEdgeG = GEOMUtils::GetEdgeNearPoint(aShape, aVertG);
545   }
546   else if (shapeType == TSHAPE_FILLET) {
547     gp_Pnt aPntG (-aR2Ext - theRF/2., 0, aR1Ext + theRF/2.);
548     aPntG.Transform(aTrsf);
549     BRepBuilderAPI_MakeVertex mkVertexG (aPntG);
550     TopoDS_Vertex aVertG = TopoDS::Vertex(mkVertexG.Shape());
551     anEdgeG = GEOMUtils::GetEdgeNearPoint(aShape, aVertG);
552   }
553
554   for (int i = 1 ; i <= aNbGroups; i++) {
555     Handle(GEOM_Object) aGroup = Handle(GEOM_Object)::DownCast(aSeqPropagate->Value(i));
556     if (aGroup.IsNull())
557       continue;
558
559     TopoDS_Shape aGroupShape = aGroup->GetValue();
560     TopTools_IndexedMapOfShape anEdgesMap;
561     TopExp::MapShapes(aGroupShape, TopAbs_EDGE, anEdgesMap);
562
563     if (anEdgesMap.Contains(anEdgeA)) { // a
564       aGroup->SetName("THICKNESS");
565       theSeq->Append(aGroup);
566     }
567     else if (anEdgesMap.Contains(anEdgeB)) { // b
568       aGroup->SetName("CIRCULAR_QUARTER_PIPE");
569       theSeq->Append(aGroup);
570     }
571     else if (anEdgesMap.Contains(anEdgeC)) { // c
572       aGroup->SetName("CIRCULAR_QUARTER_PIPE");
573       theSeq->Append(aGroup);
574     }
575     else if (anEdgesMap.Contains(anEdgeD)) { // d
576       aGroup->SetName("HALF_LENGTH_MAIN_PIPE");
577       theSeq->Append(aGroup);
578     }
579     else if (anEdgesMap.Contains(anEdgeE)) { // e
580       aGroup->SetName("HALF_LENGTH_INCIDENT_PIPE");
581       theSeq->Append(aGroup);
582     }
583     else if (anEdgesMap.Contains(anEdgeF)) { // f
584       aGroup->SetName("FLANGE");
585       theSeq->Append(aGroup);
586     }
587     else if (shapeType == TSHAPE_CHAMFER) { // g
588       if (anEdgesMap.Contains(anEdgeG)) {
589         aGroup->SetName("CHAMFER");
590         theSeq->Append(aGroup);
591       }
592     }
593     else if (shapeType == TSHAPE_FILLET) { // g
594       if (anEdgesMap.Contains(anEdgeG)) {
595         aGroup->SetName("FILLET");
596         theSeq->Append(aGroup);
597       }
598     }
599     else {
600     }
601   }
602   // END: new groups search
603 #else
604   bool addGroup;
605   bool circularFoundAndAdded = false;
606   bool circularFound10 = false;
607   bool incidentPipeFound = false;
608   bool mainPipeFound = false;
609   bool mainPipeFoundAndAdded = false;
610   bool radialFound =false;
611   bool flangeFound = false;
612   bool flangeFoundAndAdded = false;
613   bool chamferOrFilletFound = false;
614
615   for (int i = 1 ; i <= aNbGroups; i++) {
616     addGroup = false;
617
618     Handle(GEOM_Object) aGroup = Handle(GEOM_Object)::DownCast(aSeqPropagate->Value(i));
619     if (aGroup.IsNull())
620       continue;
621
622     gp_Trsf aTrsfInv = aTrsf.Inverted();
623     TopoDS_Shape aGroupShape = aGroup->GetValue();
624     BRepBuilderAPI_Transform aTransformationShapeInv (aGroupShape, aTrsfInv, Standard_False);
625     TopoDS_Shape aGroupShapeTrsfInv = aTransformationShapeInv.Shape();
626
627     TopTools_IndexedMapOfShape anEdgesMap;
628     TopExp::MapShapes(aGroupShapeTrsfInv,TopAbs_EDGE, anEdgesMap);
629     Standard_Integer nbEdges = anEdgesMap.Extent();
630
631     if (shapeType == TSHAPE_BASIC) {
632       if ((nbEdges >= 21) || /*R1Ext = R2Ext*/(nbEdges == 17)) { // 17, 17+8*{1,2,3}, 21, 21+8*{1,2,3}
633         addGroup = true;
634         aGroup->SetName("THICKNESS");
635       }
636       else if (nbEdges == 6) {
637         if (!circularFoundAndAdded) {
638           circularFoundAndAdded = true;
639           addGroup = true;
640           aGroup->SetName("CIRCULAR_QUARTER_PIPE");
641         }
642       }
643       else if (nbEdges == 8) {
644         incidentPipeFound = true;
645         mainPipeFound = false;
646         radialFound = false;
647         flangeFound = false;
648
649         TopExp_Explorer Ex(aGroupShapeTrsfInv,TopAbs_VERTEX);
650         while (Ex.More()) {
651           gp_Pnt aP =  BRep_Tool::Pnt(TopoDS::Vertex(Ex.Current()));
652           double x=aP.X(), y=aP.Y(), z=aP.Z();
653
654
655           if ((Abs(x) > aR2Ext + Precision::Confusion()) ||
656               (Abs(y) > aR2Ext + Precision::Confusion())) {
657             incidentPipeFound = false;
658           }
659
660           if ( z < -Precision::Confusion()) {
661             // length of main pipe
662             mainPipeFound = true;
663             if (!mainPipeFoundAndAdded) {
664               mainPipeFoundAndAdded = true;
665               addGroup = true;
666               aGroup->SetName("HALF_LENGTH_MAIN_PIPE");
667             }
668           }
669
670           else if (Abs(x) > (theL1-Precision::Confusion())) {
671             // discretisation circulaire
672             radialFound = true;
673             if (!circularFoundAndAdded) {
674               circularFoundAndAdded = true;
675               addGroup = true;
676               aGroup->SetName("CIRCULAR_QUARTER_PIPE");
677             }
678           }
679           Ex.Next();
680         }
681         if (incidentPipeFound) {
682           addGroup = true;
683           aGroup->SetName("HALF_LENGTH_INCIDENT_PIPE");
684         }
685         if (!addGroup && (!incidentPipeFound &&
686                           !radialFound &&
687                           !mainPipeFound &&
688                           !flangeFound)) {
689           // Flange (collerette)
690           flangeFound = true;
691           addGroup = true;
692           aGroup->SetName("FLANGE");
693         }
694       }
695       else
696         continue;
697     }
698     else if (shapeType == TSHAPE_CHAMFER || shapeType == TSHAPE_FILLET) {
699       if (nbEdges >= 25) { // 25, 25+8, 25+16, 25+24
700         addGroup = true;
701         aGroup->SetName("THICKNESS");
702       }
703       else if ((nbEdges == 10) || (nbEdges == 6)) {
704         if (!circularFoundAndAdded) {
705           addGroup = true;
706           circularFoundAndAdded = true;
707           aGroup->SetName("CIRCULAR_QUARTER_PIPE");
708           if (nbEdges == 10) {
709             circularFound10 = true;
710           }
711         }
712         else if (!circularFound10 && nbEdges == 10) {
713           circularFound10 = true;
714           addGroup = true;
715           aGroup->SetName("CIRCULAR_QUARTER_PIPE");
716         }
717       }
718       else if (nbEdges == 8) {
719         incidentPipeFound = true;
720         mainPipeFound = true;
721         flangeFound = false;
722
723         bool isNearZ0 = false;
724         bool isBelowZ0 = false;
725
726         TopExp_Explorer Ex (aGroupShapeTrsfInv,TopAbs_VERTEX);
727         while (Ex.More()) {
728           gp_Pnt aP = BRep_Tool::Pnt(TopoDS::Vertex(Ex.Current()));
729           double x=aP.X(), y=aP.Y(), z=aP.Z();
730
731           // tuy_princ_long_avant & tuy_princ_long_apres
732           //bool isMain = (((z < Precision::Confusion()) || (x < Precision::Confusion())) &&
733           //               ((y <= aR1Ext + Precision::Confusion()) ||
734           //                (y <= -(aR1Ext + Precision::Confusion())) ||
735           //                (y <= theR1 + Precision::Confusion()) ||
736           //                (y == -(theR1 + Precision::Confusion()))));
737           bool isMain = ((z < Precision::Confusion() || x < Precision::Confusion()) &&
738                          (fabs(y) > theR1 - Precision::Confusion() ||
739                           fabs(y) < Precision::Confusion()));
740
741           if (!isMain) {
742             mainPipeFound = false;
743           }
744
745           // collerette
746           //if (z < Precision::Confusion() && !isMain) {
747           //  flangeFound = true;
748           //  if (!flangeFoundAndAdded) {
749           //    flangeFoundAndAdded = true;
750           //    addGroup = true;
751           //    aGroup->SetName("FLANGE");
752           //  }
753           //}
754           if (fabs(z) < Precision::Confusion()) isNearZ0 = true;
755           if (z < - Precision::Confusion()) isBelowZ0 = true;
756
757           // tuyau incident
758           if ((Abs(x) > aR2Ext + Precision::Confusion()) ||
759               (Abs(y) > aR2Ext + Precision::Confusion())) {
760             incidentPipeFound = false;
761           }
762           Ex.Next();
763         }
764         if (mainPipeFound) {
765           addGroup = true;
766           aGroup->SetName("HALF_LENGTH_MAIN_PIPE");
767         }
768         if (incidentPipeFound) {
769           addGroup = true;
770           aGroup->SetName("HALF_LENGTH_INCIDENT_PIPE");
771         }
772         if (isNearZ0 && !isBelowZ0) {
773           flangeFound = true;
774           if (!flangeFoundAndAdded) {
775             flangeFoundAndAdded = true;
776             addGroup = true;
777             aGroup->SetName("FLANGE");
778           }
779         }
780         if (!addGroup && (!incidentPipeFound &&
781                           !mainPipeFound &&
782                           !flangeFound &&
783                           !chamferOrFilletFound)) {
784           addGroup = true;
785           chamferOrFilletFound = true;
786           if (shapeType == TSHAPE_CHAMFER)
787             aGroup->SetName("CHAMFER");
788           else
789             aGroup->SetName("FILLET");
790         }
791       }
792       else
793         continue;
794     }
795     // Add group to the list
796     if (addGroup)
797       theSeq->Append(aGroup);
798   }
799 #endif
800
801   SetErrorCode(OK);
802   return true;
803 }
804
805 //=============================================================================
806 /*!
807  *  Return faces that are laying on surface.
808  */
809 //=============================================================================
810 bool AdvancedEngine_IOperations::GetFacesOnSurf
811                      (const TopoDS_Shape &theShape,
812                       const Handle(Geom_Surface)& theSurface,
813                       const Standard_Real theTolerance,
814                       TopTools_ListOfShape &theFaces)
815 {
816   GEOMAlgo_FinderShapeOn2   aFinder;
817   Handle(GEOMAlgo_ClsfSurf) aClsfSurf = new GEOMAlgo_ClsfSurf;
818
819   aClsfSurf->SetSurface(theSurface);
820   aFinder.SetShape(theShape);
821   aFinder.SetTolerance(theTolerance);
822   aFinder.SetClsf(aClsfSurf);
823   aFinder.SetShapeType(TopAbs_FACE);
824   aFinder.SetState(GEOMAlgo_ST_ON);
825
826   // Sets the minimal number of inner points for the faces that do not have own
827   // inner points at all (for e.g. rectangular planar faces have just 2 triangles).
828   // Default value=3
829   aFinder.SetNbPntsMin(3);
830   // Sets the maximal number of inner points for edges or faces.
831   // It is useful for the cases when this number is very big (e.g =2000) to improve
832   // the performance. If this value =0, all inner points will be taken into account.
833   // Default value=0
834   aFinder.SetNbPntsMax(100);
835   aFinder.Perform();
836
837   // Interpret results
838   Standard_Integer iErr = aFinder.ErrorStatus();
839   // the detailed description of error codes is in GEOMAlgo_FinderShapeOn2.cxx
840   if (iErr) {
841     MESSAGE(" iErr : " << iErr);
842     TCollection_AsciiString aMsg (" iErr : ");
843     aMsg += TCollection_AsciiString(iErr);
844     SetErrorCode(aMsg);
845     return false;
846   }
847   Standard_Integer iWrn = aFinder.WarningStatus();
848   // the detailed description of warning codes is in GEOMAlgo_FinderShapeOn2.cxx
849   if (iWrn) {
850     MESSAGE(" *** iWrn : " << iWrn);
851   }
852
853   const TopTools_ListOfShape &aListRes = aFinder.Shapes(); // the result
854   TopTools_ListIteratorOfListOfShape anIter (aListRes);
855
856   for (; anIter.More(); anIter.Next()) {
857     theFaces.Append(anIter.Value());
858   }
859
860   return true;
861 }
862
863 //=============================================================================
864 /*!
865  *  Creates and returns conical face.
866  */
867 //=============================================================================
868 TopoDS_Shape AdvancedEngine_IOperations::MakeConicalFace
869                                   (const gp_Ax2 &theAxis,
870                                    const double theRadius,
871                                    const double theRadiusThin,
872                                    const double theHeight,
873                                    const gp_Trsf &theTrsf)
874 {
875   BRepPrimAPI_MakeCone aMkCone (theAxis, theRadius, theRadiusThin, theHeight);
876   TopoDS_Shape aResult;
877   
878   aMkCone.Build();
879   if (aMkCone.IsDone()) {
880     TopExp_Explorer anExp(aMkCone.Shape(), TopAbs_FACE);
881
882     for (; anExp.More(); anExp.Next()) {
883       TopoDS_Face aFace = TopoDS::Face(anExp.Current());
884
885       if (aFace.IsNull() == Standard_False) {
886         BRepAdaptor_Surface anAdaptor(aFace, Standard_False);
887
888         if (anAdaptor.GetType() == GeomAbs_Cone) {
889           // This is a conical face. Transform and return it.
890           BRepBuilderAPI_Transform aTransf(aFace, theTrsf, Standard_False);
891           
892           aResult = aTransf.Shape();
893           break;
894         }
895       }
896     }
897   }
898
899   return aResult;
900 }
901
902 //=============================================================================
903 /*!
904  *  Generate the internal group of a Pipe T-Shape
905  */
906 //=============================================================================
907 bool AdvancedEngine_IOperations::MakeInternalGroup
908                       (const Handle(GEOM_Object) &theShape,
909                        const double theR1, const double theLen1,
910                        const double theR2, const double theLen2,
911                        const double theRL, double theTransLenL,
912                        const double theRR, double theTransLenR,
913                        const double theRI, double theTransLenI,
914                        const Handle(TColStd_HSequenceOfTransient) &theSeq,
915                        const gp_Trsf &theTrsf)
916 {
917   SetErrorCode(KO);
918
919   if (theShape.IsNull()) {
920     return false;
921   }
922
923   TopoDS_Shape aShape = theShape->GetValue();
924
925   if (aShape.IsNull()) {
926     SetErrorCode("Shape is not defined");
927     return false;
928   }
929
930   // Compute tolerance
931   Standard_Real aMaxTol = -RealLast();
932   TopExp_Explorer anExp(aShape, TopAbs_VERTEX);
933
934   for (; anExp.More(); anExp.Next()) {
935     TopoDS_Vertex aVertex = TopoDS::Vertex(anExp.Current());
936
937     if (aVertex.IsNull() == Standard_False) {
938       const Standard_Real aTol = BRep_Tool::Tolerance(aVertex);
939
940       if (aTol > aMaxTol) {
941         aMaxTol = aTol;
942       }
943     }
944   }
945
946   // Construct internal surfaces.
947   Standard_Integer i = 0;
948   const Standard_Integer aMaxNbSurf = 5;
949   Handle(Geom_Surface) aSurface[aMaxNbSurf];
950   TopTools_ListOfShape aConicalFaces;
951   Standard_Real aTolConf = Precision::Confusion();
952
953   // 1. Construct the internal surface of main pipe.
954   gp_Ax2 anAxis1 (gp::Origin(), gp::DX(), gp::DZ());
955   gp_Ax2 anAxis2 (gp::Origin(), gp::DZ(), gp::DX());
956
957   aSurface[i++] = new Geom_CylindricalSurface(anAxis1, theR1);
958
959   // 2. Construct the internal surface of incident pipe.
960   aSurface[i++] = new Geom_CylindricalSurface(anAxis2, theR2);
961
962   // 3. Construct the internal surface of left reduction pipe.
963   if (theRL > aTolConf) {
964     aSurface[i++] = new Geom_CylindricalSurface(anAxis1, theRL);
965
966     if (theTransLenL > aTolConf) {
967       // 3.1. Construct the internal surface of left transition pipe.
968       gp_Pnt aPLeft (-theLen1, 0., 0.);
969       gp_Ax2 anAxisLeft (aPLeft, -gp::DX(), gp::DZ());
970       TopoDS_Shape aConeLeft =
971         MakeConicalFace(anAxisLeft, theR1, theRL, theTransLenL, theTrsf);
972
973       if (aConeLeft.IsNull() == Standard_False) {
974         aConicalFaces.Append(aConeLeft);
975       }
976     }
977   }
978
979   // 4. Construct the internal surface of right reduction pipe.
980   if (theRR > aTolConf) {
981     // There is no need to construct another cylinder of the same radius. Skip it.
982     if (Abs(theRR - theRL) > aTolConf) {
983       aSurface[i++] = new Geom_CylindricalSurface(anAxis1, theRR);
984     }
985
986     if (theTransLenL > aTolConf) {
987       // 4.1. Construct the internal surface of right transition pipe.
988       gp_Pnt aPRight (theLen1, 0., 0.);
989       gp_Ax2 anAxisRight (aPRight, gp::DX(), gp::DZ());
990       TopoDS_Shape aConeRight =
991         MakeConicalFace(anAxisRight, theR1, theRR, theTransLenR, theTrsf);
992
993       if (aConeRight.IsNull() == Standard_False) {
994         aConicalFaces.Append(aConeRight);
995       }
996     }
997   }
998
999   // 5. Construct the internal surface of incident reduction pipe.
1000   if (theRI > aTolConf) {
1001     aSurface[i++] = new Geom_CylindricalSurface(anAxis2, theRI);
1002
1003     if (theTransLenI > aTolConf) {
1004       // 5.1. Construct the internal surface of incident transition pipe.
1005       gp_Pnt aPInci (0., 0., theLen2);
1006       gp_Ax2 anAxisInci (aPInci, gp::DZ(), gp::DX());
1007       TopoDS_Shape aConeInci =
1008         MakeConicalFace(anAxisInci, theR2, theRI, theTransLenI, theTrsf);
1009
1010       if (aConeInci.IsNull() == Standard_False) {
1011         aConicalFaces.Append(aConeInci);
1012       }
1013     }
1014   }
1015
1016   // Get faces that are laying on cylindrical surfaces.
1017   TopTools_ListOfShape aFaces;
1018   gp_Trsf anInvTrsf = theTrsf.Inverted();
1019
1020   for (i = 0; i < aMaxNbSurf; i++) {
1021     if (aSurface[i].IsNull()) {
1022       break;
1023     }
1024
1025     aSurface[i]->Transform(theTrsf);
1026
1027     TopTools_ListOfShape aLocalFaces;
1028
1029     if (!GetFacesOnSurf(aShape, aSurface[i], aMaxTol, aLocalFaces)) {
1030       return false;
1031     }
1032
1033     if (i < 2) {
1034       // Check if the result contains outer cylinders.
1035       // It is required for main and incident pipes.
1036       TopTools_ListIteratorOfListOfShape anIter(aLocalFaces);
1037
1038       while (anIter.More()) {
1039         TopExp_Explorer anExp(anIter.Value(), TopAbs_VERTEX);
1040         Standard_Boolean isInside = Standard_False;
1041
1042         // Get a vertex from this shape
1043         if (anExp.More()) {
1044           TopoDS_Vertex aVtx = TopoDS::Vertex(anExp.Current());
1045
1046           if (aVtx.IsNull() == Standard_False) {
1047             gp_Pnt aPnt = BRep_Tool::Pnt(aVtx);
1048
1049             aPnt.Transform(anInvTrsf);
1050
1051             if (i == 0) {
1052               // Check if the point is inside the main pipe.
1053               isInside = (Abs(aPnt.X()) <= theLen1);
1054             } else { // i == 1
1055               // Check if the point is inside the incident pipe.
1056               isInside = (aPnt.Z() <= theLen2);
1057             }
1058           }
1059         }
1060
1061         if (isInside) {
1062           // Keep this face.
1063           anIter.Next();
1064         } else {
1065           // Remove this face.
1066           aLocalFaces.Remove(anIter);
1067         }
1068       }
1069     }
1070
1071     aFaces.Append(aLocalFaces);
1072   }
1073
1074   // Get faces that are laying on conical faces.
1075   if (aConicalFaces.IsEmpty() == Standard_False) {
1076     Handle(GEOM_Object) aCone =
1077       GetEngine()->AddObject(GEOM_TSHAPE);
1078     Handle(GEOM_Function) aFunction =
1079       aCone->AddFunction(AdvancedEngine_PipeTShapeDriver::GetID(), TSHAPE_BASIC);
1080     TopTools_ListIteratorOfListOfShape aFIter(aConicalFaces);
1081     Handle(GEOM_Object) aConeFromShape;
1082
1083     for (; aFIter.More(); aFIter.Next()) {
1084       aFunction->SetValue(aFIter.Value());
1085       aConeFromShape = myShapesOperations->GetInPlace(theShape, aCone);
1086
1087       if (aConeFromShape.IsNull() == Standard_False) {
1088         aConeFromShape->GetLastFunction()->SetDescription("");
1089         TopoDS_Shape aConeFaces = aConeFromShape->GetValue();
1090         TopExp_Explorer anExp(aConeFaces, TopAbs_FACE);
1091
1092         for (; anExp.More(); anExp.Next()) {
1093           TopoDS_Face aConeFace = TopoDS::Face(anExp.Current());
1094
1095           if (aConeFace.IsNull() == Standard_False) {
1096             aFaces.Append(aConeFace);
1097           }
1098         }
1099       }
1100     }
1101   }
1102
1103   // Create a group of internal faces.
1104   if (aFaces.IsEmpty() == Standard_False) {
1105     Handle(GEOM_Object) aGroup = myGroupOperations->CreateGroup(theShape, TopAbs_FACE);
1106
1107     if (aGroup.IsNull() == Standard_False) {
1108       aGroup->GetLastFunction()->SetDescription("");
1109       aGroup->SetName("INTERNAL_FACES");
1110
1111       TopTools_IndexedMapOfShape anIndices;
1112       Handle(TColStd_HSequenceOfInteger) aSeqIDs = new TColStd_HSequenceOfInteger;
1113
1114       TopExp::MapShapes(aShape, anIndices);
1115
1116       TopTools_ListIteratorOfListOfShape anIter(aFaces);
1117
1118       for (; anIter.More(); anIter.Next()) {
1119         const TopoDS_Shape &aFace = anIter.Value();
1120         const Standard_Integer anIndex = anIndices.FindIndex(aFace);
1121
1122         if (anIndex > 0) {
1123           aSeqIDs->Append(anIndex);
1124         }
1125       }
1126
1127       myGroupOperations->UnionIDs(aGroup, aSeqIDs);
1128       aGroup->GetLastFunction()->SetDescription("");
1129       theSeq->Append(aGroup);
1130     }
1131   }
1132
1133   SetErrorCode(OK);
1134
1135   return true;
1136 }
1137
1138 bool AdvancedEngine_IOperations::MakePipeTShapePartition(Handle(GEOM_Object) theShape,
1139                                                          double theR1, double theW1, double theL1,
1140                                                          double theR2, double theW2, double theL2,
1141                                                          double theH, double theW,
1142                                                          double theRF, bool isNormal)
1143 {
1144   SetErrorCode(KO);
1145
1146   // Build tools for partition operation:
1147   // 1 face and 2 planes
1148   // Face
1149   Handle(GEOM_Object) arete_intersect_int, arete_intersect_ext;
1150   Handle(GEOM_Object) wire_t, wire_t2, face_t, face_t2;
1151   Handle(GEOM_Object) chan_racc;
1152   Handle(GEOM_Object) vi1, vi2;
1153   Handle(GEOM_Object) Te3;
1154
1155   try {
1156     OCC_CATCH_SIGNALS;
1157     Handle(GEOM_Object) Vector_Z = myBasicOperations->MakeVectorDXDYDZ(0, 0, 1);
1158     Vector_Z->GetLastFunction()->SetDescription("");
1159
1160     // Useful values
1161     double aSize = 2*(theL1 + theL2);
1162     double aR1Ext = theR1 + theW1;
1163     double aR2Ext = theR2 + theW2;
1164     double theVertCylinderRadius = aR2Ext + theW + theRF;
1165     double theHoriCylinderRadius = aR1Ext + theH + theRF;
1166
1167     // Common edges on internal cylinder
1168     Handle(GEOM_Object) box_i = my3DPrimOperations->MakeBoxDXDYDZ(theR2, theR2, theR1);
1169     box_i->GetLastFunction()->SetDescription("");
1170     box_i = myTransformOperations->TranslateDXDYDZ(box_i, -theR2, -theR2, 0);
1171     box_i->GetLastFunction()->SetDescription("");
1172
1173     Handle(GEOM_Function) aFunction = theShape->GetLastFunction();
1174     TCollection_AsciiString theDesc = aFunction->GetDescription();
1175     Handle(TColStd_HSequenceOfTransient) edges_i =
1176       myShapesOperations->GetShapesOnBox(box_i, theShape, TopAbs_EDGE, GEOMAlgo_ST_IN);
1177     // Recover previous description to get rid of Propagate dump
1178     aFunction->SetDescription(theDesc);
1179     if (edges_i.IsNull() || edges_i->Length() == 0) {
1180       SetErrorCode("Internal edges not found");
1181       return false;
1182     }
1183     for (int i=1; i<=edges_i->Length();i++) {
1184       Handle(GEOM_Object) anObj = Handle(GEOM_Object)::DownCast(edges_i->Value(i));
1185       anObj->GetLastFunction()->SetDescription("");
1186     }
1187     arete_intersect_int = Handle(GEOM_Object)::DownCast(edges_i->Value(1));
1188
1189     // search for vertices located on both internal pipes
1190     aFunction = theShape->GetLastFunction();
1191     theDesc = aFunction->GetDescription();
1192     Handle(TColStd_HSequenceOfTransient) vertices_i =
1193       myShapesOperations->GetShapesOnBox(box_i, theShape, TopAbs_VERTEX, GEOMAlgo_ST_ONIN);
1194     // Recover previous description to get rid of Propagate dump
1195     aFunction->SetDescription(theDesc);
1196     if (vertices_i.IsNull() || vertices_i->Length() == 0) {
1197       SetErrorCode("Internal vertices not found");
1198       return false;
1199     }
1200
1201     double d1min = theR2+theW2, d2min=theR2+theW2;
1202     for (int i = 1; i <= vertices_i->Length(); i++) {
1203       Handle(GEOM_Object) v = Handle(GEOM_Object)::DownCast(vertices_i->Value(i));
1204       v->GetLastFunction()->SetDescription("");
1205       TopoDS_Vertex aVertex = TopoDS::Vertex(v->GetValue());
1206       gp_Pnt aP = BRep_Tool::Pnt(aVertex);
1207       if (Abs(aP.X()) <= Precision::Confusion()) {
1208         if (Abs(aP.Y()) < d1min) {
1209           vi1 = v;
1210           d1min = Abs(aP.Y());
1211         }
1212       } else if (Abs(aP.Y()) <= Precision::Confusion()) {
1213         if (Abs(aP.X()) < d2min) {
1214           vi2 = v;
1215           d2min = Abs(aP.X());
1216         }
1217       }
1218     }
1219     if (vi1.IsNull() || vi2.IsNull()) {
1220       SetErrorCode("Cannot find internal intersection vertices");
1221       return false;
1222     }
1223
1224     std::list<Handle(GEOM_Object)> theShapes;
1225
1226     if (isNormal) {
1227       Handle(GEOM_Object) ve1, ve2;
1228       TopoDS_Vertex vertex1, vertex2;
1229
1230       Handle(GEOM_Object) box_e = my3DPrimOperations->MakeBoxDXDYDZ(aR2Ext, aR2Ext, aR1Ext);
1231       box_e->GetLastFunction()->SetDescription("");
1232       box_e = myTransformOperations->TranslateDXDYDZ(box_e, -aR2Ext, -aR2Ext, 0);
1233       box_e->GetLastFunction()->SetDescription("");
1234
1235       // search for vertices located on both external pipes
1236       aFunction = theShape->GetLastFunction();
1237       theDesc = aFunction->GetDescription();
1238       Handle(TColStd_HSequenceOfTransient) vertices_e =
1239         myShapesOperations->GetShapesOnBox(box_e, theShape, TopAbs_VERTEX, GEOMAlgo_ST_ONIN);
1240       // Recover previous description to get rid of Propagate dump
1241       aFunction->SetDescription(theDesc);
1242       if (vertices_e.IsNull() || vertices_e->Length() == 0) {
1243         SetErrorCode("External vertices not found");
1244         return false;
1245       }
1246
1247       double d1max = 0, d2max = 0;
1248       for (int i = 1; i <= vertices_e->Length(); i++) {
1249         Handle(GEOM_Object) v = Handle(GEOM_Object)::DownCast(vertices_e->Value(i));
1250         v->GetLastFunction()->SetDescription("");
1251         TopoDS_Vertex aVertex = TopoDS::Vertex(v->GetValue());
1252         gp_Pnt aP = BRep_Tool::Pnt(aVertex);
1253         if (Abs(aP.X()) <= Precision::Confusion()) {
1254           if (Abs(aP.Y()) > d1max) {
1255             ve1 = v;
1256             vertex1 = aVertex;
1257             d1max = Abs(aP.Y());
1258           }
1259         } else if (Abs(aP.Y()) <= Precision::Confusion()) {
1260           if (Abs(aP.X()) > d2max) {
1261             ve2 = v;
1262             vertex2 = aVertex;
1263             d2max = Abs(aP.X());
1264           }
1265         }
1266       }
1267       if (ve1.IsNull() || ve2.IsNull()) {
1268         SetErrorCode("Cannot find external intersection vertices");
1269         return false;
1270       }
1271       Handle(GEOM_Object) edge_e1, edge_e2;
1272
1273       // Common edges on external cylinder
1274       aFunction = theShape->GetLastFunction();
1275       theDesc = aFunction->GetDescription();
1276       Handle(TColStd_HSequenceOfTransient) edges_e =
1277         myShapesOperations->GetShapesOnBox(box_e, theShape, TopAbs_EDGE, GEOMAlgo_ST_IN);
1278       // Recover previous description to get rid of Propagate dump
1279       aFunction->SetDescription(theDesc);
1280       if (edges_e.IsNull() || edges_e->Length() == 0) {
1281         SetErrorCode("External edges not found");
1282         return false;
1283       }
1284       ShapeAnalysis_Edge sae;
1285       for (int i=1; i<=edges_e->Length();i++) {
1286         Handle(GEOM_Object) anObj = Handle(GEOM_Object)::DownCast(edges_e->Value(i));
1287         anObj->GetLastFunction()->SetDescription("");
1288         TopoDS_Edge anEdge = TopoDS::Edge(anObj->GetValue());
1289         if ( !anEdge.IsNull() && 
1290              (sae.FirstVertex(anEdge).IsSame(vertex1) || sae.LastVertex(anEdge).IsSame(vertex1)) && 
1291              (sae.FirstVertex(anEdge).IsSame(vertex2) || sae.LastVertex(anEdge).IsSame(vertex2))) {
1292           arete_intersect_ext = anObj;
1293         }
1294       }
1295
1296       edge_e1 = myBasicOperations->MakeLineTwoPnt(ve1, vi1);
1297       if (edge_e1.IsNull()) {
1298         SetErrorCode("Edge 1 could not be built");
1299         return false;
1300       }
1301
1302       edge_e2 = myBasicOperations->MakeLineTwoPnt(ve2, vi2);
1303       if (edge_e2.IsNull()) {
1304         SetErrorCode("Edge 2 could not be built");
1305         return false;
1306       }
1307
1308       edge_e1->GetLastFunction()->SetDescription("");
1309       edge_e2->GetLastFunction()->SetDescription("");
1310
1311       std::list<Handle(GEOM_Object)> edge_e_elist;
1312       edge_e_elist.push_back(arete_intersect_int);
1313       edge_e_elist.push_back(edge_e1);
1314       edge_e_elist.push_back(arete_intersect_ext);
1315       edge_e_elist.push_back(edge_e2);
1316       wire_t = myShapesOperations->MakeWire(edge_e_elist, 1e-7);
1317       if (wire_t.IsNull()) {
1318         SetErrorCode("Impossible to build wire");
1319         return false;
1320       }
1321       wire_t->GetLastFunction()->SetDescription("");
1322       face_t = myShapesOperations->MakeFace(wire_t, false);
1323       if (face_t.IsNull()) {
1324         SetErrorCode("Impossible to build face");
1325         return false;
1326       }
1327       face_t->GetLastFunction()->SetDescription("");
1328
1329       theShapes.push_back(theShape);
1330       theShapes.push_back(vi1);
1331       theShapes.push_back(vi2);
1332       theShapes.push_back(ve1);
1333       theShapes.push_back(ve2);
1334       theShapes.push_back(edge_e1);
1335       theShapes.push_back(edge_e2);
1336       theShapes.push_back(wire_t);
1337       theShapes.push_back(face_t);
1338     }
1339     else {
1340       Handle(GEOM_Object) P1, P2, P3, P4, P5, P6;
1341       int idP1, idP2, idP3, idP4;
1342       int PZX=0, PZY=0; // todo: PZX, PZY must be explicitly initialized to avoid warning (see below)
1343       double ZX=0, ZY=0;
1344       std::vector<int> LX;
1345       std::vector<int> LY;
1346       Handle(GEOM_Object) box_e = my3DPrimOperations->MakeBoxDXDYDZ
1347         (theVertCylinderRadius, theVertCylinderRadius, theHoriCylinderRadius);
1348       box_e->GetLastFunction()->SetDescription("");
1349       box_e = myTransformOperations->TranslateDXDYDZ
1350         (box_e, -theVertCylinderRadius, -theVertCylinderRadius, 0);
1351       box_e->GetLastFunction()->SetDescription("");
1352
1353       aFunction = theShape->GetLastFunction();
1354       theDesc = aFunction->GetDescription();
1355       Handle(TColStd_HSequenceOfTransient) extremVertices =
1356         myShapesOperations->GetShapesOnBox(box_e, theShape, TopAbs_VERTEX, GEOMAlgo_ST_ONIN);
1357       // Recover previous description to get rid of Propagate dump
1358       aFunction->SetDescription(theDesc);
1359
1360       if (extremVertices.IsNull() || extremVertices->Length() == 0) {
1361         if (theRF == 0)
1362           SetErrorCode("Vertices on chamfer not found");
1363         else
1364           SetErrorCode("Vertices on fillet not found");
1365         return false;
1366       }
1367
1368       theShapes.push_back(theShape);
1369       theShapes.push_back(box_e);
1370       if (extremVertices->Length() != 6) {
1371         //           for (int i=1; i<=extremVertices->Length(); i++){
1372         //             theShapes.push_back(Handle(GEOM_Object)::DownCast(extremVertices->Value(i)));
1373         //           }
1374         //           Handle(GEOM_Object) aCompound = myShapesOperations->MakeCompound(theShapes);
1375         //           TopoDS_Shape aCompoundShape = aCompound->GetValue();
1376         //           theShape->GetLastFunction()->SetValue(aCompoundShape);
1377         SetErrorCode("Bad number of vertices on chamfer found");
1378         return false;
1379       }
1380
1381       for (int i=1; i<=extremVertices->Length(); i++){
1382         Handle(GEOM_Object) aV = Handle(GEOM_Object)::DownCast(extremVertices->Value(i));
1383         aV->GetLastFunction()->SetDescription("");
1384         gp_Pnt aP = BRep_Tool::Pnt(TopoDS::Vertex(aV->GetValue()));
1385
1386         if (Abs(aP.X()) <= Precision::Confusion()) {
1387           if (Abs(aP.Y()) - theR2 > Precision::Confusion()) {
1388             LX.push_back(i);
1389             if  (aP.Z()-ZX > Precision::Confusion()) {
1390               ZX = aP.Z();
1391               PZX = i;
1392             }
1393           }
1394         }
1395         else {
1396           if (Abs(aP.X()) - theR2 > Precision::Confusion()) {
1397             LY.push_back(i);
1398             if (aP.Z() - ZY > Precision::Confusion()) {
1399               ZY = aP.Z();
1400               PZY = i;
1401             }
1402           }
1403         }
1404       }
1405
1406       idP2 = PZX;
1407       idP4 = PZY;
1408       idP1 = LX.at(0);
1409       if (LX.at(0) == PZX)
1410         idP1 = LX.at(1);
1411       idP3 = LY.at(0);
1412       if (LY.at(0) == PZY)
1413         idP3 = LY.at(1);
1414
1415       P1 = Handle(GEOM_Object)::DownCast(extremVertices->Value(idP1));
1416       P2 = Handle(GEOM_Object)::DownCast(extremVertices->Value(idP2)); // todo: PZX must be explicitly initialized to avoid warning (see above)
1417       P3 = Handle(GEOM_Object)::DownCast(extremVertices->Value(idP3));
1418       P4 = Handle(GEOM_Object)::DownCast(extremVertices->Value(idP4)); // todo: PZY must be explicitly initialized to avoid warning (see above)
1419
1420       Handle(GEOM_Object) Cote_1 = myBasicOperations->MakeLineTwoPnt(P1, vi1);
1421       if (Cote_1.IsNull()) {
1422         SetErrorCode("Impossible to build edge in thickness");
1423         return false;
1424       }
1425       Cote_1->GetLastFunction()->SetDescription("");
1426
1427       Handle(GEOM_Object) Cote_2 = myBasicOperations->MakeLineTwoPnt(vi2, P3);
1428       if (Cote_2.IsNull()) {
1429         SetErrorCode("Impossible to build edge in thickness");
1430         return false;
1431       }
1432       Cote_2->GetLastFunction()->SetDescription("");
1433
1434       // edge_chan_princ = arete du chanfrein (ou raccord) sur le tuyau principal
1435       // edge_chan_inc = arete du chanfrein (ou raccord) sur le tuyau incident
1436       //         std::cerr << "Getting chamfer edge on main pipe" << std::endl;
1437       Handle(GEOM_Object) edge_chan_princ = myBlocksOperations->GetEdge(theShape, P1, P3);
1438       if (edge_chan_princ.IsNull()) {
1439         SetErrorCode("Impossible to find edge on main pipe");
1440         return false;
1441       }
1442       edge_chan_princ->GetLastFunction()->SetDescription("");
1443
1444       Handle(GEOM_Object) edge_chan_inc = myBlocksOperations->GetEdge(theShape, P2, P4);
1445       if (edge_chan_inc.IsNull()) {
1446         SetErrorCode("Impossible to find edge on incident pipe");
1447         return false;
1448       }
1449       edge_chan_inc->GetLastFunction()->SetDescription("");
1450
1451       std::list<Handle(GEOM_Object)> edgeList1;
1452       edgeList1.push_back(edge_chan_princ);
1453       edgeList1.push_back(Cote_1);
1454       edgeList1.push_back(arete_intersect_int);
1455       edgeList1.push_back(Cote_2);
1456
1457       //         std::cerr << "Creating wire 1" << std::endl;
1458       wire_t = myShapesOperations->MakeWire(edgeList1, 1e-7);
1459       if (wire_t.IsNull()) {
1460         SetErrorCode("Impossible to build wire");
1461         return false;
1462       }
1463       wire_t->GetLastFunction()->SetDescription("");
1464
1465       //         std::cerr << "Creating face 1" << std::endl;
1466       face_t = myShapesOperations->MakeFace(wire_t, false);
1467       if (face_t.IsNull()) {
1468         SetErrorCode("Impossible to build face");
1469         return false;
1470       }
1471       face_t->GetLastFunction()->SetDescription("");
1472       theShapes.push_back(face_t);
1473
1474       // Create a prism from edge_chan_inc
1475       Handle(GEOM_Object) aPrismDir = myBasicOperations->MakeVectorDXDYDZ(1., 1., 0.);
1476
1477       if (aPrismDir.IsNull()) {
1478         SetErrorCode("Impossible to build Prism direction");
1479         return false;
1480       }
1481       aPrismDir->GetLastFunction()->SetDescription("");
1482       face_t2 = my3DPrimOperations->MakePrismVecH(edge_chan_inc, aPrismDir, theR2 + theW2);
1483
1484       if (face_t2.IsNull()) {
1485         SetErrorCode("Impossible to build face");
1486         return false;
1487       }
1488       face_t2->GetLastFunction()->SetDescription("");
1489       theShapes.push_back(face_t2);
1490     }
1491
1492     // Planes
1493     Handle(GEOM_Object) aP0 = myBasicOperations->MakePointXYZ(0, 0, 0);
1494     Handle(GEOM_Object) aVZ = myBasicOperations->MakeVectorDXDYDZ(0, 0, 1);
1495     Handle(GEOM_Object) aVXZ = myBasicOperations->MakeVectorDXDYDZ(aR1Ext, 0, 0.5*(theL1+theVertCylinderRadius));
1496     Handle(GEOM_Object) aPlnOZ = myBasicOperations->MakePlanePntVec(aP0, aVZ, aSize);
1497     Handle(GEOM_Object) aPlnOXZ = myBasicOperations->MakePlanePntVec(aP0, aVXZ, aSize);
1498     aP0->GetLastFunction()->SetDescription("");
1499     aVZ->GetLastFunction()->SetDescription("");
1500     aVXZ->GetLastFunction()->SetDescription("");
1501     aPlnOZ->GetLastFunction()->SetDescription("");
1502     aPlnOXZ->GetLastFunction()->SetDescription("");
1503     theShapes.push_back(aPlnOZ);
1504     theShapes.push_back(aPlnOXZ);
1505
1506     // Partition
1507     Handle(TColStd_HSequenceOfTransient) partitionShapes = new TColStd_HSequenceOfTransient;
1508     Handle(TColStd_HSequenceOfTransient) theTools = new TColStd_HSequenceOfTransient;
1509     Handle(TColStd_HSequenceOfTransient) theKeepInside = new TColStd_HSequenceOfTransient;
1510     Handle(TColStd_HSequenceOfTransient) theRemoveInside = new TColStd_HSequenceOfTransient;
1511     Handle(TColStd_HArray1OfInteger) theMaterials;
1512
1513     partitionShapes->Append(theShape);
1514     theTools->Append(aPlnOZ);
1515     if (Abs(aR1Ext - aR2Ext) > Precision::Confusion())
1516       theTools->Append(aPlnOXZ);
1517     theTools->Append(face_t);
1518     if (!isNormal)
1519       theTools->Append(face_t2);
1520
1521     Te3 = myBooleanOperations->MakePartition
1522               (partitionShapes, theTools, theKeepInside, theRemoveInside,
1523               TopAbs_SOLID, false, theMaterials, 0, false, Standard_False);
1524     if (Te3.IsNull()) {
1525       SetErrorCode("Impossible to build partition of TShape");
1526       return false;
1527     }
1528     Te3->GetLastFunction()->SetDescription("");
1529
1530     // Last verification: result should be a block
1531     std::list<GEOMImpl_IBlocksOperations::BCError> errList;
1532     if (!myBlocksOperations->CheckCompoundOfBlocks(Te3, -1, errList)) {
1533       SetErrorCode("TShape is not a compound of block");
1534       return false;
1535     }
1536
1537 //     // BEGIN Compound of created shapes - Only for debug purpose
1538 //     theShapes.clear();
1539 //     theShapes.push_back(theShape);
1540 //     theShapes.push_back(aPlnOZ);
1541 //     if (Abs(aR1Ext - aR2Ext) > Precision::Confusion() )
1542 //       theShapes.push_back(aPlnOXZ);
1543 //     theShapes.push_back(face_t);
1544 //     if (!isNormal)
1545 //       theShapes.push_back(face_t2);
1546 //
1547 //     Handle(GEOM_Object) aCompound = myShapesOperations->MakeCompound(theShapes);
1548 //     TopoDS_Shape aCompoundShape = aCompound->GetValue();
1549 //     theShape->GetLastFunction()->SetValue(aCompoundShape);
1550 //     // END Compound of created shapes - Only for debug purpose
1551
1552     TopoDS_Shape aShape = Te3->GetValue();
1553     theShape->GetLastFunction()->SetValue(aShape);
1554   }
1555   catch (Standard_Failure& aFail) {
1556     SetErrorCode(aFail.GetMessageString());
1557     return false;
1558   }
1559
1560   SetErrorCode(OK);
1561   return true;
1562 }
1563
1564 // Mirror and glue faces
1565 bool AdvancedEngine_IOperations::MakePipeTShapeMirrorAndGlue(Handle(GEOM_Object) theShape,
1566                                                              double theR1, double theW1, double theL1,
1567                                                              double /*theR2*/, double /*theW2*/, double theL2)
1568 {
1569   SetErrorCode(KO);
1570
1571   // Useful values
1572   double aSize = 2*(theL1 + theL2);
1573   double aR1Ext = theR1 + theW1;
1574
1575   // Planes
1576   Handle(GEOM_Object) aP0 = myBasicOperations->MakePointXYZ(0, 0, 0);
1577   aP0->GetLastFunction()->SetDescription("");
1578   Handle(GEOM_Object) aVX = myBasicOperations->MakeVectorDXDYDZ(1, 0, 0);
1579   Handle(GEOM_Object) aVY = myBasicOperations->MakeVectorDXDYDZ(0, 1, 0);
1580   aVX->GetLastFunction()->SetDescription("");
1581   aVY->GetLastFunction()->SetDescription("");
1582   Handle(GEOM_Object) aPlane_OX = myBasicOperations->MakePlanePntVec(aP0, aVX, 2*(aR1Ext + theL2));
1583   Handle(GEOM_Object) aPlane_OY = myBasicOperations->MakePlanePntVec(aP0, aVY, aSize);
1584   aPlane_OX->GetLastFunction()->SetDescription("");
1585   aPlane_OY->GetLastFunction()->SetDescription("");
1586
1587   Handle(GEOM_Object) Te4 = myTransformOperations->MirrorPlaneCopy(theShape, aPlane_OX);
1588   if (Te4.IsNull()) {
1589     SetErrorCode("Impossible to build mirror of quarter TShape");
1590     return false;
1591   }
1592
1593   Handle(GEOM_Object) Te5 = myTransformOperations->MirrorPlaneCopy(theShape, aPlane_OY);
1594   if (Te5.IsNull()) {
1595     SetErrorCode("Impossible to build mirror of half TShape");
1596     return false;
1597   }
1598
1599   Handle(GEOM_Object) Te6 = myTransformOperations->MirrorPlaneCopy(Te4, aPlane_OY);
1600   if (Te6.IsNull()) {
1601     SetErrorCode("Impossible to build mirror of half TShape");
1602     return false;
1603   }
1604
1605   std::list<Handle(GEOM_Object)> aShapesList;
1606   aShapesList.push_back(theShape);
1607   aShapesList.push_back(Te4);
1608   aShapesList.push_back(Te5);
1609   aShapesList.push_back(Te6);
1610   Handle(GEOM_Object) Te7 = myShapesOperations->MakeCompound(aShapesList);
1611   if (Te7.IsNull()) {
1612     SetErrorCode("Impossible to build compound");
1613     return false;
1614   }
1615
1616   // Copy source shape
1617   TopoDS_Shape aShapeCopy;
1618   TColStd_IndexedDataMapOfTransientTransient aMapTShapes;
1619   TNaming_CopyShape::CopyTool(Te7->GetValue(), aMapTShapes, aShapeCopy);
1620
1621   std::list<Handle(GEOM_Object)> Te7list( 1, Te7 );
1622   Handle(GEOM_Object) Te8 = myShapesOperations->MakeGlueFaces(Te7list, 1e-7, true);
1623   if (Te8.IsNull()) {
1624     SetErrorCode("Impossible to glue faces of TShape");
1625     return false;
1626   }
1627
1628   TopoDS_Shape aShape = Te8->GetValue();
1629   BRepCheck_Analyzer anAna (aShape, Standard_True);
1630
1631   if (!anAna.IsValid()) {
1632     // Try to do gluing with the tolerance equal to maximal
1633     // tolerance of vertices of the source shape.
1634     Standard_Real aTolMax = -RealLast();
1635
1636     for (TopExp_Explorer ExV (aShapeCopy, TopAbs_VERTEX); ExV.More(); ExV.Next()) {
1637       TopoDS_Vertex aVertex = TopoDS::Vertex(ExV.Current());
1638       Standard_Real aTol = BRep_Tool::Tolerance(aVertex);
1639
1640       if (aTol > aTolMax) {
1641         aTolMax = aTol;
1642       }
1643     }
1644
1645     // Perform gluing
1646     Te7->GetLastFunction()->SetValue(aShapeCopy);
1647     Te8 = myShapesOperations->MakeGlueFaces(Te7list, aTolMax, true);
1648
1649     if (Te8.IsNull()) {
1650       SetErrorCode("Impossible to glue faces of TShape");
1651       return false;
1652     }
1653
1654     aShape = Te8->GetValue();
1655   }
1656
1657
1658   theShape->GetLastFunction()->SetValue(aShape);
1659
1660   Te4->GetLastFunction()->SetDescription("");
1661   Te5->GetLastFunction()->SetDescription("");
1662   Te6->GetLastFunction()->SetDescription("");
1663   Te7->GetLastFunction()->SetDescription("");
1664   Te8->GetLastFunction()->SetDescription("");
1665
1666   SetErrorCode(OK);
1667   return true;
1668 }
1669
1670 //=======================================================================
1671 //function : MakePipeTShapeThicknessReduction
1672 //purpose  : Static method. Add thiskness reduction elements at the three
1673 //                          open ends of the T-Shape.
1674 //=======================================================================
1675 TopoDS_Shape AdvancedEngine_IOperations::MakePipeTShapeThicknessReduction
1676                                   (TopoDS_Shape theShape,
1677                                    double r1, double w1, double l1,
1678                                    double r2, double w2, double l2,
1679                                    double rL, double wL, double ltransL, double lthinL,
1680                                    double rR, double wR, double ltransR, double lthinR,
1681                                    double rI, double wI, double ltransI, double lthinI,
1682                                    bool fuseReductions)
1683 {
1684   // Add thickness reduction elements
1685   // at the three extremities: Left, Right and Incident
1686   /*
1687      ---------------------.
1688        W                   \
1689      ---------------------. \
1690        ^                   \ '-----------------.
1691        |R                   \        Wthin     |
1692        |                     '-----------------'
1693        v                             Rthin
1694      --.--.--.--.--.--.--.--.--.--.--.--.--.--.--
1695                          Ltrans    Lthin
1696   */
1697
1698   TopoDS_Shape aResult = theShape;
1699   double aTol = Precision::Confusion();
1700
1701   gp_Vec aVX = gp::DX(), aVZ = gp::DZ();
1702
1703   // Left reduction (rL, wL, ltransL, lthinL)
1704   if (rL > aTol && wL > aTol && ltransL > aTol) {
1705     gp_Pnt aPLeft (-l1, 0, 0);
1706     gp_Ax2 anAxesLeft (aPLeft, -aVX, aVZ);
1707     TopoDS_Shape aReductionLeft = AdvancedEngine_IOperations::MakeThicknessReduction
1708       (anAxesLeft, r1, w1, rL, wL, ltransL, lthinL, fuseReductions);
1709
1710     if (fuseReductions) {
1711       BRepAlgoAPI_Fuse fuseL (aResult, aReductionLeft);
1712       if (!fuseL.IsDone())
1713         StdFail_NotDone::Raise("Cannot fuse Te with left reduction");
1714       aResult = fuseL.Shape();
1715     }
1716     else {
1717       BRep_Builder B;
1718       TopoDS_Compound C;
1719       B.MakeCompound(C);
1720       B.Add(C, aResult);
1721       B.Add(C, aReductionLeft);
1722       aResult = C;
1723     }
1724   }
1725
1726   // Right reduction
1727   if (rR > aTol && wR > aTol && ltransR > aTol) {
1728     gp_Pnt aPRight (l1, 0, 0);
1729     gp_Ax2 anAxesRight (aPRight, aVX, aVZ);
1730     TopoDS_Shape aReductionRight = AdvancedEngine_IOperations::MakeThicknessReduction
1731       (anAxesRight, r1, w1, rR, wR, ltransR, lthinR, fuseReductions);
1732
1733     if (fuseReductions) {
1734       BRepAlgoAPI_Fuse fuseR (aResult, aReductionRight);
1735       if (!fuseR.IsDone())
1736         StdFail_NotDone::Raise("Cannot fuse Te with right reduction");
1737       aResult = fuseR.Shape();
1738     }
1739     else {
1740       BRep_Builder B;
1741       TopoDS_Compound C;
1742       B.MakeCompound(C);
1743       B.Add(C, aResult);
1744       B.Add(C, aReductionRight);
1745       aResult = C;
1746     }
1747   }
1748
1749   // Incident reduction
1750   if (rI > aTol && wI > aTol && ltransI > aTol) {
1751     gp_Pnt aPInci (0, 0, l2);
1752     gp_Ax2 anAxesInci (aPInci, aVZ, aVX);
1753     TopoDS_Shape aReductionInci = AdvancedEngine_IOperations::MakeThicknessReduction
1754       (anAxesInci, r2, w2, rI, wI, ltransI, lthinI, fuseReductions);
1755
1756     if (fuseReductions) {
1757       BRepAlgoAPI_Fuse fuseInci (aResult, aReductionInci);
1758       if (!fuseInci.IsDone())
1759         StdFail_NotDone::Raise("Cannot fuse Te with incident reduction");
1760       aResult = fuseInci.Shape();
1761     }
1762     else {
1763       BRep_Builder B;
1764       TopoDS_Compound C;
1765       B.MakeCompound(C);
1766       B.Add(C, aResult);
1767       B.Add(C, aReductionInci);
1768       aResult = C;
1769     }
1770   }
1771
1772   // Get rid of extra compounds
1773   TopTools_ListOfShape listShapeRes;
1774   GEOMUtils::AddSimpleShapes(aResult, listShapeRes);
1775   aResult = listShapeRes.First(); // useful for the case "fuseReductions == true"
1776
1777   if (!fuseReductions && listShapeRes.Extent() > 1) {
1778     // Simplify T-Shape compound (get rid of sub-compounds) and glue duplicated faces
1779     BRep_Builder B;
1780     TopoDS_Compound C;
1781     B.MakeCompound(C);
1782
1783     TopTools_ListIteratorOfListOfShape itSub (listShapeRes);
1784     for (; itSub.More(); itSub.Next())
1785       B.Add(C, itSub.Value());
1786
1787     // GlueFaces
1788     aResult = GEOMImpl_GlueDriver::GlueFaces(C, Precision::Confusion(), Standard_True);
1789   }
1790
1791   return aResult;
1792 }
1793
1794 //=======================================================================
1795 //function : MakeThicknessReduction
1796 //purpose  : Static method. Create one thickness reduction element.
1797 //=======================================================================
1798 TopoDS_Shape AdvancedEngine_IOperations::MakeThicknessReduction (gp_Ax2 theAxes,
1799                                                                  const double R, const double W,
1800                                                                  const double Rthin, const double Wthin,
1801                                                                  const double Ltrans, const double Lthin,
1802                                                                  bool fuse)
1803 {
1804   double aTol = Precision::Confusion();
1805   if (Rthin < aTol || Wthin < aTol || Ltrans < aTol) {
1806     StdFail_NotDone::Raise("Cannot build thickness reduction: too small values");
1807   }
1808   bool isThinPart = (Lthin > aTol);
1809
1810   /*
1811          .
1812        W |\
1813          . \
1814        ^  \ '-----------------.
1815        |R  \|                 | Wthin
1816        |    '-----------------'
1817        v                        Rthin
1818      --.--.--.--.--.--.--.--.--.--.--.--.--> theAxes.Direction()
1819          Ltrans     Lthin
1820   */
1821
1822   double RExt = R + W;
1823   double RthinExt = Rthin + Wthin;
1824
1825   gp_Dir aNormal = theAxes.Direction();
1826   gp_Dir anXDir  = theAxes.XDirection();
1827   gp_Pnt aPntCyl (theAxes.Location().XYZ() + aNormal.XYZ()*Ltrans);
1828   gp_Ax2 anAxesCyl (aPntCyl, aNormal, anXDir);
1829
1830   // Build the transition part
1831   BRepPrimAPI_MakeCone ConeExt (theAxes, RExt, RthinExt, Ltrans);
1832   BRepPrimAPI_MakeCone ConeInt (theAxes, R, Rthin, Ltrans);
1833   ConeExt.Build();
1834   ConeInt.Build();
1835   if (!ConeExt.IsDone() || !ConeInt.IsDone())
1836     StdFail_NotDone::Raise("Cannot build cones of thickness reduction");
1837   BRepAlgoAPI_Cut cut1 (ConeExt.Shape(), ConeInt.Shape());
1838   if (!cut1.IsDone())
1839     StdFail_NotDone::Raise("Couldn't build transition part of thickness reduction");
1840   TopoDS_Shape aReduction = cut1.Shape();
1841
1842   // Build the thin part, if required
1843   TopoDS_Shape aThinPart;
1844   if (isThinPart) {
1845     BRepPrimAPI_MakeCylinder CExt (anAxesCyl, RthinExt, Lthin);
1846     BRepPrimAPI_MakeCylinder CInt (anAxesCyl, Rthin, Lthin);
1847     CExt.Build();
1848     CInt.Build();
1849     if (!CExt.IsDone() || !CInt.IsDone())
1850       StdFail_NotDone::Raise("Cannot build cylinders of thickness reduction");
1851     BRepAlgoAPI_Cut cut2 (CExt.Shape(), CInt.Shape());
1852     if (!cut2.IsDone())
1853       StdFail_NotDone::Raise("Couldn't build thin part of thickness reduction");
1854     aThinPart = cut2.Shape();
1855   }
1856
1857   // Join parts
1858   if (fuse) {
1859     if (isThinPart) {
1860       BRepAlgoAPI_Fuse fuse1 (aReduction, aThinPart);
1861       if (!fuse1.IsDone())
1862         StdFail_NotDone::Raise("Cannot fuse parts of thickness reduction");
1863       aReduction = fuse1.Shape();
1864     }
1865   }
1866   else {
1867     // Partition the reduction on blocks
1868     gp_Ax3 anAxesPln1 (aPntCyl, theAxes.XDirection(), aNormal);
1869     gp_Ax3 anAxesPln2 (aPntCyl, theAxes.YDirection(), aNormal);
1870     gp_Pln aPln1 (anAxesPln1);
1871     gp_Pln aPln2 (anAxesPln2);
1872     double aSize = Ltrans + Lthin + R + Rthin + Wthin; // to guarantee enough size in all directions
1873     TopoDS_Shape aTool1 = BRepBuilderAPI_MakeFace(aPln1, -aSize, +aSize, -aSize, +aSize).Shape();
1874     TopoDS_Shape aTool2 = BRepBuilderAPI_MakeFace(aPln2, -aSize, +aSize, -aSize, +aSize).Shape();
1875
1876     GEOMAlgo_Splitter PS;
1877     PS.AddArgument(aReduction);
1878     if (isThinPart)
1879       PS.AddArgument(aThinPart);
1880     PS.AddTool(aTool1);
1881     PS.AddTool(aTool2);
1882     PS.SetLimit(TopAbs_SOLID);
1883     PS.Perform();
1884
1885     aReduction = PS.Shape();
1886   }
1887
1888   return aReduction;
1889 }
1890
1891 //=============================================================================
1892 /*!
1893  *  MakePipeTShape
1894  *  \brief Create a T-shape object with specified caracteristics for the main and
1895  *         the incident pipes (radius, width, half-length).
1896  *         Center of the shape is (0,0,0). The main plane of the T-shape is XOY.
1897  *  \param theR1 Internal radius of main pipe
1898  *  \param theW1 Width of main pipe
1899  *  \param theL1 Half-length of main pipe
1900  *  \param theR2 Internal radius of incident pipe (R2 < R1)
1901  *  \param theW2 Width of incident pipe (R2+W2 < R1+W1)
1902  *  \param theL2 Half-length of incident pipe
1903  *  \param theHexMesh Boolean indicating if shape is prepared for hex mesh
1904  *  \return List of GEOM_Objects, containing the created shape and propagation groups.
1905  */
1906 //=============================================================================
1907 Handle(TColStd_HSequenceOfTransient)
1908   AdvancedEngine_IOperations::MakePipeTShape(double theR1, double theW1, double theL1,
1909                                              double theR2, double theW2, double theL2,
1910                                              double theRL, double theWL, double theLtransL, double theLthinL,
1911                                              double theRR, double theWR, double theLtransR, double theLthinR,
1912                                              double theRI, double theWI, double theLtransI, double theLthinI,
1913                                              bool theHexMesh)
1914 {
1915   MESSAGE("AdvancedEngine_IOperations::MakePipeTShape");
1916   SetErrorCode(KO);
1917   //Add a new object
1918   Handle(GEOM_Object) aShape = GetEngine()->AddObject(GEOM_TSHAPE);
1919
1920   //Add a new shape function with parameters
1921   Handle(GEOM_Function) aFunction = aShape->AddFunction(AdvancedEngine_PipeTShapeDriver::GetID(), TSHAPE_BASIC);
1922   if (aFunction.IsNull()) return NULL;
1923
1924   //Check if the function is set correctly
1925   if (aFunction->GetDriverGUID() != AdvancedEngine_PipeTShapeDriver::GetID()) return NULL;
1926
1927   AdvancedEngine_IPipeTShape aData (aFunction);
1928
1929   aData.SetR1(theR1);
1930   aData.SetW1(theW1);
1931   aData.SetL1(theL1);
1932   aData.SetR2(theR2);
1933   aData.SetW2(theW2);
1934   aData.SetL2(theL2);
1935   aData.SetHexMesh(theHexMesh);
1936
1937   bool isTRL = (theRL + theWL + theLtransL + theLthinL) > Precision::Confusion();
1938   bool isTRR = (theRR + theWR + theLtransR + theLthinR) > Precision::Confusion();
1939   bool isTRI = (theRI + theWI + theLtransI + theLthinI) > Precision::Confusion();
1940
1941   //Compute the resulting value
1942   try {
1943     OCC_CATCH_SIGNALS;
1944     if (!GetSolver()->ComputeFunction(aFunction)) {
1945       SetErrorCode("TShape driver failed");
1946       return NULL;
1947     }
1948
1949     if (theHexMesh) {
1950       if (!MakePipeTShapePartition(aShape, theR1, theW1, theL1, theR2, theW2, theL2))
1951         return NULL;
1952       if (!MakePipeTShapeMirrorAndGlue(aShape, theR1, theW1, theL1, theR2, theW2, theL2))
1953         return NULL;
1954     }
1955
1956     if (isTRL || isTRR || isTRI) {
1957       // Add thickness reduction elements
1958       // at the three extremities: Left, Right and Incident
1959       TopoDS_Shape aResShape =
1960         MakePipeTShapeThicknessReduction(aShape->GetValue(), theR1, theW1, theL1, theR2, theW2, theL2,
1961                                          theRL, theWL, theLtransL, theLthinL,
1962                                          theRR, theWR, theLtransR, theLthinR,
1963                                          theRI, theWI, theLtransI, theLthinI,
1964                                          !theHexMesh);
1965       aFunction->SetValue(aResShape);
1966     }
1967   }
1968   catch (Standard_Failure& aFail) {
1969     SetErrorCode(aFail.GetMessageString());
1970     return NULL;
1971   }
1972
1973   Handle(TColStd_HSequenceOfTransient) aSeq = new TColStd_HSequenceOfTransient;
1974   aSeq->Append(aShape);
1975
1976   try {
1977     if (theHexMesh) {
1978       // Get the groups
1979       if (!MakeGroups(aShape, TSHAPE_BASIC, theR1, theW1, theL1, theR2, theW2, theL2,
1980                       0., 0., 0., aSeq, gp_Trsf()))
1981         return NULL;
1982     }
1983
1984     // Get internal group.
1985     if (!MakeInternalGroup(aShape, theR1, theL1, theR2, theL2, theRL, theLtransL,
1986                            theRR, theLtransR, theRI, theLtransI,
1987                            aSeq, gp_Trsf())) {
1988       return NULL;
1989     }
1990   }
1991   catch (Standard_Failure& aFail) {
1992     SetErrorCode(aFail.GetMessageString());
1993     return NULL;
1994   }
1995
1996   //Make a Python command
1997   TCollection_AsciiString anEntry, aListRes("[");
1998   // Iterate over the sequence aSeq
1999   Standard_Integer aNbGroups = aSeq->Length();
2000   Standard_Integer i = 1;
2001   for (; i <= aNbGroups; i++) {
2002     Handle(Standard_Transient) anItem = aSeq->Value(i);
2003     if (anItem.IsNull()) continue;
2004     Handle(GEOM_Object) aGroup = Handle(GEOM_Object)::DownCast(anItem);
2005     if (aGroup.IsNull()) continue;
2006     //Make a Python command
2007     TDF_Tool::Entry(aGroup->GetEntry(), anEntry);
2008     aListRes += anEntry + ", ";
2009   }
2010   aListRes.Trunc(aListRes.Length() - 2);
2011
2012   GEOM::TPythonDump pd (aFunction);
2013
2014   pd << aListRes.ToCString() << "] = geompy.MakePipeTShape("
2015      << theR1 << ", " << theW1 << ", " << theL1 << ", "
2016      << theR2 << ", " << theW2 << ", " << theL2 << ", "
2017      << theHexMesh;
2018
2019   // thickness reduction
2020   if (isTRL)
2021     pd << ", theRL=" << theRL << ", theWL=" << theWL
2022        << ", theLtransL=" << theLtransL << ", theLthinL=" << theLthinL;
2023   if (isTRR)
2024     pd << ", theRR=" << theRR << ", theWR=" << theWR
2025        << ", theLtransR=" << theLtransR << ", theLthinR=" << theLthinR;
2026   if (isTRI)
2027     pd << ", theRI=" << theRI << ", theWI=" << theWI
2028        << ", theLtransI=" << theLtransI << ", theLthinI=" << theLthinI;
2029
2030   pd << ")";
2031
2032   SetErrorCode(OK);
2033
2034   return aSeq;
2035 }
2036
2037 //=============================================================================
2038 /*!
2039  *  MakePipeTShapeWithPosition
2040  *  Create a T-shape object with specified caracteristics for the main and
2041  *  the incident pipes (radius, width, half-length).
2042  *  The extremities of the main pipe are located on junctions points P1 and P2.
2043  *  The extremity of the incident pipe is located on junction point P3.
2044  *  \param theR1 Internal radius of main pipe
2045  *  \param theW1 Width of main pipe
2046  *  \param theL1 Half-length of main pipe
2047  *  \param theR2 Internal radius of incident pipe (R2 < R1)
2048  *  \param theW2 Width of incident pipe (R2+W2 < R1+W1)
2049  *  \param theL2 Half-length of incident pipe
2050  *  \param theHexMesh Boolean indicating if shape is prepared for hex mesh
2051  *  \param theP1 1st junction point of main pipe
2052  *  \param theP2 2nd junction point of main pipe
2053  *  \param theP3 Junction point of incident pipe
2054  *  \return List of GEOM_Objects, containing the created shape and propagation groups..
2055  */
2056 //=============================================================================
2057 Handle(TColStd_HSequenceOfTransient)
2058 AdvancedEngine_IOperations::MakePipeTShapeWithPosition
2059                              (double theR1, double theW1, double theL1,
2060                               double theR2, double theW2, double theL2,
2061                               double theRL, double theWL, double theLtransL, double theLthinL,
2062                               double theRR, double theWR, double theLtransR, double theLthinR,
2063                               double theRI, double theWI, double theLtransI, double theLthinI,
2064                               bool theHexMesh,
2065                               Handle(GEOM_Object) theP1,
2066                               Handle(GEOM_Object) theP2,
2067                               Handle(GEOM_Object) theP3)
2068 {
2069   SetErrorCode(KO);
2070   //Add a new object
2071   Handle(GEOM_Object) aShape = GetEngine()->AddObject(GEOM_TSHAPE);
2072   /////////////////
2073   // TSHAPE CODE
2074   /////////////////
2075   //Add a new shape function with parameters
2076   Handle(GEOM_Function) aFunction = aShape->AddFunction(AdvancedEngine_PipeTShapeDriver::GetID(), TSHAPE_BASIC);
2077   if (aFunction.IsNull()) return NULL;
2078
2079   //Check if the function is set correctly
2080   if (aFunction->GetDriverGUID() != AdvancedEngine_PipeTShapeDriver::GetID()) return NULL;
2081
2082   // Check new position
2083   if (!CheckCompatiblePosition(theL1, theL2, theP1, theP2, theP3, 0.01)) {
2084     return NULL;
2085   }
2086
2087   AdvancedEngine_IPipeTShape aData(aFunction);
2088
2089   aData.SetR1(theR1);
2090   aData.SetW1(theW1);
2091   aData.SetL1(theL1);
2092   aData.SetR2(theR2);
2093   aData.SetW2(theW2);
2094   aData.SetL2(theL2);
2095   aData.SetHexMesh(theHexMesh);
2096
2097   bool isTRL = (theRL + theWL + theLtransL + theLthinL) > Precision::Confusion();
2098   bool isTRR = (theRR + theWR + theLtransR + theLthinR) > Precision::Confusion();
2099   bool isTRI = (theRI + theWI + theLtransI + theLthinI) > Precision::Confusion();
2100
2101   //Compute the resulting value
2102   try {
2103     OCC_CATCH_SIGNALS;
2104     if (!GetSolver()->ComputeFunction(aFunction)) {
2105       SetErrorCode("TShape driver failed");
2106       return NULL;
2107     }
2108
2109     if (theHexMesh) {
2110       if (!MakePipeTShapePartition(aShape, theR1, theW1, theL1, theR2, theW2, theL2))
2111         return NULL;
2112       if (!MakePipeTShapeMirrorAndGlue(aShape, theR1, theW1, theL1, theR2, theW2, theL2))
2113         return NULL;
2114     }
2115
2116     if (isTRL || isTRR || isTRI) {
2117       // Add thickness reduction elements
2118       // at the three extremities: Left, Right and Incident
2119       TopoDS_Shape aResShape =
2120         MakePipeTShapeThicknessReduction(aShape->GetValue(), theR1, theW1, theL1, theR2, theW2, theL2,
2121                                          theRL, theWL, theLtransL, theLthinL,
2122                                          theRR, theWR, theLtransR, theLthinR,
2123                                          theRI, theWI, theLtransI, theLthinI,
2124                                          !theHexMesh);
2125       aFunction->SetValue(aResShape);
2126     }
2127   }
2128   catch (Standard_Failure& aFail) {
2129     SetErrorCode(aFail.GetMessageString());
2130     return NULL;
2131   }
2132
2133   TopoDS_Shape Te = aShape->GetValue();
2134
2135   // Set Position
2136   gp_Trsf aTrsf = GetPositionTrsf(theL1, theL2, theP1, theP2, theP3);
2137   BRepBuilderAPI_Transform aTransformation(Te, aTrsf, Standard_False);
2138   TopoDS_Shape aTrsf_Shape = aTransformation.Shape();
2139   aFunction->SetValue(aTrsf_Shape);
2140
2141   Handle(TColStd_HSequenceOfTransient) aSeq = new TColStd_HSequenceOfTransient;
2142   aSeq->Append(aShape);
2143
2144   try {
2145     if (theHexMesh) {
2146       // Get the groups
2147       if (!MakeGroups(aShape,TSHAPE_BASIC, theR1, theW1, theL1, theR2, theW2, theL2,
2148                       0., 0., 0., aSeq, aTrsf)) {
2149         return NULL;
2150       }
2151     }
2152
2153     // Get internal group.
2154     if (!MakeInternalGroup(aShape, theR1, theL1, theR2, theL2, theRL, theLtransL,
2155                            theRR, theLtransR, theRI, theLtransI,
2156                            aSeq, aTrsf)) {
2157       return NULL;
2158     }
2159   }
2160   catch (Standard_Failure& aFail) {
2161     SetErrorCode(aFail.GetMessageString());
2162     return NULL;
2163   }
2164
2165   //Make a Python command
2166   TCollection_AsciiString anEntry, aListRes("[");
2167   // Iterate over the sequence aSeq
2168   Standard_Integer aNbGroups = aSeq->Length();
2169   Standard_Integer i = 1;
2170   for (; i <= aNbGroups; i++) {
2171     Handle(Standard_Transient) anItem = aSeq->Value(i);
2172     if (anItem.IsNull()) continue;
2173     Handle(GEOM_Object) aGroup = Handle(GEOM_Object)::DownCast(anItem);
2174     if (aGroup.IsNull()) continue;
2175     //Make a Python command
2176     TDF_Tool::Entry(aGroup->GetEntry(), anEntry);
2177     aListRes += anEntry + ", ";
2178   }
2179   aListRes.Trunc(aListRes.Length() - 2);
2180
2181   GEOM::TPythonDump pd (aFunction);
2182
2183   pd << aListRes.ToCString() << "] = geompy.MakePipeTShape("
2184      << theR1 << ", " << theW1 << ", " << theL1 << ", "
2185      << theR2 << ", " << theW2 << ", " << theL2 << ", "
2186      << theHexMesh << ", " << theP1 << ", " << theP2 << ", " << theP3;
2187
2188   // thickness reduction
2189   if (isTRL)
2190     pd << ", theRL=" << theRL << ", theWL=" << theWL
2191        << ", theLtransL=" << theLtransL << ", theLthinL=" << theLthinL;
2192   if (isTRR)
2193     pd << ", theRR=" << theRR << ", theWR=" << theWR
2194        << ", theLtransR=" << theLtransR << ", theLthinR=" << theLthinR;
2195   if (isTRI)
2196     pd << ", theRI=" << theRI << ", theWI=" << theWI
2197        << ", theLtransI=" << theLtransI << ", theLthinI=" << theLthinI;
2198
2199   pd << ")";
2200
2201   SetErrorCode(OK);
2202
2203   return aSeq;
2204 }
2205
2206 //=============================================================================
2207 /*!
2208  *  MakePipeTShapeChamfer
2209  *  Create a T-shape object with specified caracteristics for the main and
2210  *  the incident pipes (radius, width, half-length). A chamfer is created
2211  *  on the junction of the pipes.
2212  *  Center of the shape is (0,0,0). The main plane of the T-shape is XOY.
2213  *  \param theR1 Internal radius of main pipe
2214  *  \param theW1 Width of main pipe
2215  *  \param theL1 Half-length of main pipe
2216  *  \param theR2 Internal radius of incident pipe (R2 < R1)
2217  *  \param theW2 Width of incident pipe (R2+W2 < R1+W1)
2218  *  \param theL2 Half-length of incident pipe
2219  *  \param theH Height of chamfer.
2220  *  \param theW Width of chamfer.
2221  *  \param theHexMesh Boolean indicating if shape is prepared for hex mesh
2222  *  \return List of GEOM_Objects, containing the created shape and propagation groups.
2223  */
2224 //=============================================================================
2225 Handle(TColStd_HSequenceOfTransient)
2226 AdvancedEngine_IOperations::MakePipeTShapeChamfer
2227                              (double theR1, double theW1, double theL1,
2228                               double theR2, double theW2, double theL2,
2229                               double theRL, double theWL, double theLtransL, double theLthinL,
2230                               double theRR, double theWR, double theLtransR, double theLthinR,
2231                               double theRI, double theWI, double theLtransI, double theLthinI,
2232                               double theH, double theW,
2233                               bool theHexMesh)
2234 {
2235   SetErrorCode(KO);
2236   //Add a new object
2237   Handle(GEOM_Object) aShape = GetEngine()->AddObject(GEOM_TSHAPE);
2238   //Add a new shape function with parameters
2239   Handle(GEOM_Function) aFunction = aShape->AddFunction(AdvancedEngine_PipeTShapeDriver::GetID(), TSHAPE_CHAMFER);
2240   if (aFunction.IsNull()) return NULL;
2241
2242   //Check if the function is set correctly
2243   if (aFunction->GetDriverGUID() != AdvancedEngine_PipeTShapeDriver::GetID()) return NULL;
2244
2245   AdvancedEngine_IPipeTShape aData(aFunction);
2246
2247   aData.SetR1(theR1);
2248   aData.SetW1(theW1);
2249   aData.SetL1(theL1);
2250   aData.SetR2(theR2);
2251   aData.SetW2(theW2);
2252   aData.SetL2(theL2);
2253   aData.SetH(theH);
2254   aData.SetW(theW);
2255   aData.SetHexMesh(theHexMesh);
2256
2257   bool isTRL = (theRL + theWL + theLtransL + theLthinL) > Precision::Confusion();
2258   bool isTRR = (theRR + theWR + theLtransR + theLthinR) > Precision::Confusion();
2259   bool isTRI = (theRI + theWI + theLtransI + theLthinI) > Precision::Confusion();
2260
2261   //Compute the resulting value
2262   try {
2263     OCC_CATCH_SIGNALS;
2264     if (!GetSolver()->ComputeFunction(aFunction)) {
2265       SetErrorCode("TShape driver failed");
2266       return NULL;
2267     }
2268   }
2269   catch (Standard_Failure& aFail) {
2270     SetErrorCode(aFail.GetMessageString());
2271     return NULL;
2272   }
2273
2274   // BEGIN of chamfer
2275   TopoDS_Shape aShapeShape = aShape->GetValue();
2276   TopTools_IndexedMapOfShape anEdgesIndices;
2277   TopExp::MapShapes(aShapeShape, anEdgesIndices);
2278   // Common edges on external cylinders
2279   Handle(GEOM_Object) box_e;
2280   if (theHexMesh) {
2281     box_e = my3DPrimOperations->MakeBoxDXDYDZ(theR2+theW2, theR2+theW2, theR1+theW1);
2282   }
2283   else {
2284     box_e = my3DPrimOperations->MakeBoxDXDYDZ(2*(theR2+theW2), 2*(theR2+theW2), theR1+theW1);
2285   }
2286   box_e->GetLastFunction()->SetDescription("");
2287   box_e = myTransformOperations->TranslateDXDYDZ(box_e, -(theR2+theW2), -(theR2+theW2), 0);
2288   box_e->GetLastFunction()->SetDescription("");
2289
2290   Handle(TColStd_HSequenceOfInteger) edges_e =
2291     myShapesOperations->GetShapesOnBoxIDs(box_e, aShape, TopAbs_EDGE, GEOMAlgo_ST_IN);
2292   box_e->GetLastFunction()->SetDescription("");
2293
2294   if (edges_e.IsNull() || edges_e->Length() == 0) {
2295     SetErrorCode("External edges not found");
2296     return NULL;
2297   }
2298   int nbEdgesInChamfer = 0;
2299   std::list<int> theEdges;
2300   for (int i=1; i<=edges_e->Length();i++) {
2301     int edgeID = edges_e->Value(i);
2302     TopoDS_Shape theEdge = anEdgesIndices.FindKey(edgeID);
2303     TopExp_Explorer Ex(theEdge,TopAbs_VERTEX);
2304     int iv=0;
2305     while (Ex.More()) {
2306       iv ++;
2307       gp_Pnt aPt = BRep_Tool::Pnt(TopoDS::Vertex(Ex.Current()));
2308       if (Abs(aPt.Z() - (theR1+theW1)) <= Precision::Confusion()) {
2309         nbEdgesInChamfer ++;
2310         theEdges.push_back(edgeID);
2311       }
2312       Ex.Next();
2313     }
2314     if (theHexMesh && nbEdgesInChamfer == 1)
2315       break;
2316   }
2317   Handle(GEOM_Object) aChamfer;
2318   try {
2319     aChamfer = myLocalOperations->MakeChamferEdges(aShape, theW, theH, theEdges);
2320   }
2321   catch (Standard_Failure& aFail) {
2322     SetErrorCode(aFail.GetMessageString());
2323     return NULL;
2324   }
2325   if (aChamfer.IsNull()) {
2326     SetErrorCode("Chamfer can not be computed on the given shape with the given parameters");
2327     return NULL;
2328   }
2329   aChamfer->GetLastFunction()->SetDescription("");
2330
2331   TopoDS_Shape aChamferShape = aChamfer->GetValue();
2332   aFunction->SetValue(aChamferShape);
2333   // END of chamfer
2334
2335   if (theHexMesh) {
2336     if (!MakePipeTShapePartition(aShape, theR1, theW1, theL1, theR2, theW2, theL2, theH, theW, 0, false))
2337       return NULL;
2338     if (!MakePipeTShapeMirrorAndGlue(aShape, theR1, theW1, theL1, theR2, theW2, theL2))
2339       return NULL;
2340   }
2341
2342   // Add thickness reduction elements
2343   // at the three extremities: Left, Right and Incident
2344   try {
2345     OCC_CATCH_SIGNALS;
2346     if (isTRL || isTRR || isTRI) {
2347       TopoDS_Shape aResShape =
2348         MakePipeTShapeThicknessReduction(aShape->GetValue(), theR1, theW1, theL1, theR2, theW2, theL2,
2349                                          theRL, theWL, theLtransL, theLthinL,
2350                                          theRR, theWR, theLtransR, theLthinR,
2351                                          theRI, theWI, theLtransI, theLthinI,
2352                                          !theHexMesh);
2353       aFunction->SetValue(aResShape);
2354     }
2355   }
2356   catch (Standard_Failure& aFail) {
2357     SetErrorCode(aFail.GetMessageString());
2358     return NULL;
2359   }
2360
2361   Handle(TColStd_HSequenceOfTransient) aSeq = new TColStd_HSequenceOfTransient;
2362   aSeq->Append(aShape);
2363
2364   try {
2365     if (theHexMesh) {
2366       // Get the groups
2367       if (!MakeGroups(aShape, TSHAPE_CHAMFER, theR1, theW1, theL1, theR2, theW2, theL2,
2368                       theH, theW, 0., aSeq, gp_Trsf()))
2369         return NULL;
2370     }
2371
2372     // Get internal group.
2373     if (!MakeInternalGroup(aShape, theR1, theL1, theR2, theL2, theRL, theLtransL,
2374                            theRR, theLtransR, theRI, theLtransI,
2375                            aSeq, gp_Trsf())) {
2376       return NULL;
2377     }
2378   }
2379   catch (Standard_Failure& aFail) {
2380     SetErrorCode(aFail.GetMessageString());
2381     return NULL;
2382   }
2383
2384   //Make a Python command
2385   TCollection_AsciiString anEntry, aListRes("[");
2386   // Iterate over the sequence aSeq
2387   Standard_Integer aNbGroups = aSeq->Length();
2388   Standard_Integer i = 1;
2389   for (; i <= aNbGroups; i++) {
2390     Handle(Standard_Transient) anItem = aSeq->Value(i);
2391     if (anItem.IsNull()) continue;
2392     Handle(GEOM_Object) aGroup = Handle(GEOM_Object)::DownCast(anItem);
2393     if (aGroup.IsNull()) continue;
2394     //Make a Python command
2395     TDF_Tool::Entry(aGroup->GetEntry(), anEntry);
2396     aListRes += anEntry + ", ";
2397   }
2398   aListRes.Trunc(aListRes.Length() - 2);
2399
2400   GEOM::TPythonDump pd (aFunction);
2401
2402   pd << aListRes.ToCString() << "] = geompy.MakePipeTShapeChamfer("
2403      << theR1 << ", " << theW1 << ", " << theL1 << ", "
2404      << theR2 << ", " << theW2 << ", " << theL2 << ", "
2405      << theH << ", " << theW << ", " << theHexMesh;
2406
2407   // thickness reduction
2408   if (isTRL)
2409     pd << ", theRL=" << theRL << ", theWL=" << theWL
2410        << ", theLtransL=" << theLtransL << ", theLthinL=" << theLthinL;
2411   if (isTRR)
2412     pd << ", theRR=" << theRR << ", theWR=" << theWR
2413        << ", theLtransR=" << theLtransR << ", theLthinR=" << theLthinR;
2414   if (isTRI)
2415     pd << ", theRI=" << theRI << ", theWI=" << theWI
2416        << ", theLtransI=" << theLtransI << ", theLthinI=" << theLthinI;
2417
2418   pd << ")";
2419
2420   SetErrorCode(OK);
2421
2422   return aSeq;
2423 }
2424
2425 //=============================================================================
2426 /*!
2427  *  MakePipeTShapeChamferWithPosition
2428  *  Create a T-shape object with specified caracteristics for the main and
2429  *  the incident pipes (radius, width, half-length). A chamfer is created
2430  *  on the junction of the pipes.
2431  *  The extremities of the main pipe are located on junctions points P1 and P2.
2432  *  The extremity of the incident pipe is located on junction point P3.
2433  *  \param theR1 Internal radius of main pipe
2434  *  \param theW1 Width of main pipe
2435  *  \param theL1 Half-length of main pipe
2436  *  \param theR2 Internal radius of incident pipe (R2 < R1)
2437  *  \param theW2 Width of incident pipe (R2+W2 < R1+W1)
2438  *  \param theL2 Half-length of incident pipe
2439  *  \param theH Height of chamfer.
2440  *  \param theW Width of chamfer.
2441  *  \param theHexMesh Boolean indicating if shape is prepared for hex mesh
2442  *  \param theP1 1st junction point of main pipe
2443  *  \param theP2 2nd junction point of main pipe
2444  *  \param theP3 Junction point of incident pipe
2445  *  \return List of GEOM_Objects, containing the created shape and propagation groups.
2446  */
2447 //=============================================================================
2448 Handle(TColStd_HSequenceOfTransient)
2449 AdvancedEngine_IOperations::MakePipeTShapeChamferWithPosition
2450                              (double theR1, double theW1, double theL1,
2451                               double theR2, double theW2, double theL2,
2452                               double theRL, double theWL, double theLtransL, double theLthinL,
2453                               double theRR, double theWR, double theLtransR, double theLthinR,
2454                               double theRI, double theWI, double theLtransI, double theLthinI,
2455                               double theH, double theW,
2456                               bool theHexMesh,
2457                               Handle(GEOM_Object) theP1,
2458                               Handle(GEOM_Object) theP2,
2459                               Handle(GEOM_Object) theP3)
2460 {
2461   SetErrorCode(KO);
2462   //Add a new object
2463   Handle(GEOM_Object) aShape = GetEngine()->AddObject(GEOM_TSHAPE);
2464   //Add a new shape function with parameters
2465   Handle(GEOM_Function) aFunction = aShape->AddFunction(AdvancedEngine_PipeTShapeDriver::GetID(), TSHAPE_CHAMFER);
2466   if (aFunction.IsNull()) return NULL;
2467
2468   //Check if the function is set correctly
2469   if (aFunction->GetDriverGUID() != AdvancedEngine_PipeTShapeDriver::GetID()) return NULL;
2470
2471   // Check new position
2472   if (!CheckCompatiblePosition(theL1, theL2, theP1, theP2, theP3, 0.01)) {
2473     return NULL;
2474   }
2475
2476   AdvancedEngine_IPipeTShape aData(aFunction);
2477
2478   aData.SetR1(theR1);
2479   aData.SetW1(theW1);
2480   aData.SetL1(theL1);
2481   aData.SetR2(theR2);
2482   aData.SetW2(theW2);
2483   aData.SetL2(theL2);
2484   aData.SetH(theH);
2485   aData.SetW(theW);
2486   aData.SetHexMesh(theHexMesh);
2487
2488   bool isTRL = (theRL + theWL + theLtransL + theLthinL) > Precision::Confusion();
2489   bool isTRR = (theRR + theWR + theLtransR + theLthinR) > Precision::Confusion();
2490   bool isTRI = (theRI + theWI + theLtransI + theLthinI) > Precision::Confusion();
2491
2492   //Compute the resulting value
2493   try {
2494     OCC_CATCH_SIGNALS;
2495     if (!GetSolver()->ComputeFunction(aFunction)) {
2496       SetErrorCode("TShape driver failed");
2497       return NULL;
2498     }
2499   }
2500   catch (Standard_Failure& aFail) {
2501     SetErrorCode(aFail.GetMessageString());
2502     return NULL;
2503   }
2504
2505   // BEGIN of chamfer
2506   TopoDS_Shape aShapeShape = aShape->GetValue();
2507   TopTools_IndexedMapOfShape anEdgesIndices;
2508   TopExp::MapShapes(aShapeShape, anEdgesIndices);
2509   // Common edges on external cylinders
2510   Handle(GEOM_Object) box_e;
2511   if (theHexMesh) {
2512     box_e = my3DPrimOperations->MakeBoxDXDYDZ(theR2+theW2, theR2+theW2, theR1+theW1);
2513   }
2514   else {
2515     box_e = my3DPrimOperations->MakeBoxDXDYDZ(2*(theR2+theW2), 2*(theR2+theW2), theR1+theW1);
2516   }
2517   box_e->GetLastFunction()->SetDescription("");
2518   box_e = myTransformOperations->TranslateDXDYDZ(box_e, -(theR2+theW2), -(theR2+theW2), 0);
2519   box_e->GetLastFunction()->SetDescription("");
2520
2521   Handle(TColStd_HSequenceOfInteger) edges_e =
2522     myShapesOperations->GetShapesOnBoxIDs(box_e, aShape, TopAbs_EDGE, GEOMAlgo_ST_IN);
2523   box_e->GetLastFunction()->SetDescription("");
2524
2525   if (edges_e.IsNull() || edges_e->Length() == 0) {
2526     SetErrorCode("External edges not found");
2527     return NULL;
2528   }
2529   int nbEdgesInChamfer = 0;
2530   std::list<int> theEdges;
2531   for (int i=1; i<=edges_e->Length();i++) {
2532     int edgeID = edges_e->Value(i);
2533     TopoDS_Shape theEdge = anEdgesIndices.FindKey(edgeID);
2534     TopExp_Explorer Ex(theEdge,TopAbs_VERTEX);
2535     while (Ex.More()) {
2536       gp_Pnt aPt = BRep_Tool::Pnt(TopoDS::Vertex(Ex.Current()));
2537       if (Abs(aPt.Z() - (theR1+theW1)) <= Precision::Confusion()) {
2538         nbEdgesInChamfer ++;
2539         theEdges.push_back(edgeID);
2540       }
2541       Ex.Next();
2542     }
2543     if (theHexMesh && nbEdgesInChamfer == 1)
2544       break;
2545   }
2546   Handle(GEOM_Object) aChamfer;
2547   try {
2548     aChamfer = myLocalOperations->MakeChamferEdges(aShape, theW, theH, theEdges);
2549   }
2550   catch (Standard_Failure& aFail) {
2551     SetErrorCode(aFail.GetMessageString());
2552     return NULL;
2553   }
2554   if (aChamfer.IsNull()) {
2555     SetErrorCode("Chamfer can not be computed on the given shape with the given parameters");
2556     return NULL;
2557   }
2558   aChamfer->GetLastFunction()->SetDescription("");
2559
2560   TopoDS_Shape aChamferShape = aChamfer->GetValue();
2561   aFunction->SetValue(aChamferShape);
2562   // END of chamfer
2563
2564   if (theHexMesh) {
2565     if (!MakePipeTShapePartition(aShape, theR1, theW1, theL1, theR2, theW2, theL2, theH, theW, 0, false))
2566       return NULL;
2567     if (!MakePipeTShapeMirrorAndGlue(aShape, theR1, theW1, theL1, theR2, theW2, theL2))
2568       return NULL;
2569   }
2570
2571   // Add thickness reduction elements
2572   // at the three extremities: Left, Right and Incident
2573   try {
2574     OCC_CATCH_SIGNALS;
2575     if (isTRL || isTRR || isTRI) {
2576       TopoDS_Shape aResShape =
2577         MakePipeTShapeThicknessReduction(aShape->GetValue(), theR1, theW1, theL1, theR2, theW2, theL2,
2578                                          theRL, theWL, theLtransL, theLthinL,
2579                                          theRR, theWR, theLtransR, theLthinR,
2580                                          theRI, theWI, theLtransI, theLthinI,
2581                                          !theHexMesh);
2582       aFunction->SetValue(aResShape);
2583     }
2584   }
2585   catch (Standard_Failure& aFail) {
2586     SetErrorCode(aFail.GetMessageString());
2587     return NULL;
2588   }
2589
2590   // Set Position
2591   gp_Trsf aTrsf = GetPositionTrsf(theL1, theL2, theP1, theP2, theP3);
2592   BRepBuilderAPI_Transform aTransformation (aShape->GetValue(), aTrsf, Standard_False);
2593   TopoDS_Shape aTrsf_Shape = aTransformation.Shape();
2594   aFunction->SetValue(aTrsf_Shape);
2595
2596   Handle(TColStd_HSequenceOfTransient) aSeq = new TColStd_HSequenceOfTransient;
2597   aSeq->Append(aShape);
2598
2599   try {
2600     if (theHexMesh) {
2601       // Get the groups
2602       if (!MakeGroups(aShape, TSHAPE_CHAMFER, theR1, theW1, theL1, theR2, theW2, theL2,
2603                       theH, theW, 0., aSeq, aTrsf))
2604         return NULL;
2605     }
2606
2607     // Get internal group.
2608     if (!MakeInternalGroup(aShape, theR1, theL1, theR2, theL2, theRL, theLtransL,
2609                            theRR, theLtransR, theRI, theLtransI,
2610                            aSeq, aTrsf)) {
2611       return NULL;
2612     }
2613   }
2614   catch (Standard_Failure& aFail) {
2615     SetErrorCode(aFail.GetMessageString());
2616     return NULL;
2617   }
2618
2619   //Make a Python command
2620   TCollection_AsciiString anEntry, aListRes("[");
2621   // Iterate over the sequence aSeq
2622   Standard_Integer aNbGroups = aSeq->Length();
2623   Standard_Integer i = 1;
2624   for (; i <= aNbGroups; i++) {
2625     Handle(Standard_Transient) anItem = aSeq->Value(i);
2626     if (anItem.IsNull()) continue;
2627     Handle(GEOM_Object) aGroup = Handle(GEOM_Object)::DownCast(anItem);
2628     if (aGroup.IsNull()) continue;
2629     //Make a Python command
2630     TDF_Tool::Entry(aGroup->GetEntry(), anEntry);
2631     aListRes += anEntry + ", ";
2632   }
2633   aListRes.Trunc(aListRes.Length() - 2);
2634
2635   GEOM::TPythonDump pd (aFunction);
2636
2637   pd << aListRes.ToCString() << "] = geompy.MakePipeTShapeChamfer("
2638      << theR1 << ", " << theW1 << ", " << theL1 << ", "
2639      << theR2 << ", " << theW2 << ", " << theL2 << ", "
2640      << theH << ", " << theW << ", " << theHexMesh << ", "
2641      << theP1 << ", " << theP2 << ", " << theP3;
2642
2643   // thickness reduction
2644   if (isTRL)
2645     pd << ", theRL=" << theRL << ", theWL=" << theWL
2646        << ", theLtransL=" << theLtransL << ", theLthinL=" << theLthinL;
2647   if (isTRR)
2648     pd << ", theRR=" << theRR << ", theWR=" << theWR
2649        << ", theLtransR=" << theLtransR << ", theLthinR=" << theLthinR;
2650   if (isTRI)
2651     pd << ", theRI=" << theRI << ", theWI=" << theWI
2652        << ", theLtransI=" << theLtransI << ", theLthinI=" << theLthinI;
2653
2654   pd << ")";
2655
2656   SetErrorCode(OK);
2657
2658   return aSeq;
2659 }
2660
2661 //=============================================================================
2662 /*!
2663  *  MakePipeTShapeFillet
2664  *  Create a T-shape object with specified caracteristics for the main and
2665  *  the incident pipes (radius, width, half-length). A fillet is created
2666  *  on the junction of the pipes.
2667  *  Center of the shape is (0,0,0). The main plane of the T-shape is XOY.
2668  *  \param theR1 Internal radius of main pipe
2669  *  \param theW1 Width of main pipe
2670  *  \param theL1 Half-length of main pipe
2671  *  \param theR2 Internal radius of incident pipe (R2 < R1)
2672  *  \param theW2 Width of incident pipe (R2+W2 < R1+W1)
2673  *  \param theL2 Half-length of incident pipe
2674  *  \param theRF Radius of curvature of fillet.
2675  *  \param theHexMesh Boolean indicating if shape is prepared for hex mesh
2676  *  \return List of GEOM_Objects, containing the created shape and propagation groups.
2677  */
2678 //=============================================================================
2679 Handle(TColStd_HSequenceOfTransient)
2680 AdvancedEngine_IOperations::MakePipeTShapeFillet
2681                              (double theR1, double theW1, double theL1,
2682                               double theR2, double theW2, double theL2,
2683                               double theRL, double theWL, double theLtransL, double theLthinL,
2684                               double theRR, double theWR, double theLtransR, double theLthinR,
2685                               double theRI, double theWI, double theLtransI, double theLthinI,
2686                               double theRF, bool theHexMesh)
2687 {
2688   SetErrorCode(KO);
2689   //Add a new object
2690   Handle(GEOM_Object) aShape = GetEngine()->AddObject(GEOM_TSHAPE);
2691   //Add a new shape function with parameters
2692   Handle(GEOM_Function) aFunction = aShape->AddFunction(AdvancedEngine_PipeTShapeDriver::GetID(), TSHAPE_FILLET);
2693   if (aFunction.IsNull()) return NULL;
2694
2695   //Check if the function is set correctly
2696   if (aFunction->GetDriverGUID() != AdvancedEngine_PipeTShapeDriver::GetID()) return NULL;
2697
2698   AdvancedEngine_IPipeTShape aData(aFunction);
2699
2700   aData.SetR1(theR1);
2701   aData.SetW1(theW1);
2702   aData.SetL1(theL1);
2703   aData.SetR2(theR2);
2704   aData.SetW2(theW2);
2705   aData.SetL2(theL2);
2706   aData.SetRF(theRF);
2707   aData.SetHexMesh(theHexMesh);
2708
2709   bool isTRL = (theRL + theWL + theLtransL + theLthinL) > Precision::Confusion();
2710   bool isTRR = (theRR + theWR + theLtransR + theLthinR) > Precision::Confusion();
2711   bool isTRI = (theRI + theWI + theLtransI + theLthinI) > Precision::Confusion();
2712
2713   //Compute the resulting value
2714   try {
2715     OCC_CATCH_SIGNALS;
2716     if (!GetSolver()->ComputeFunction(aFunction)) {
2717       SetErrorCode("TShape driver failed");
2718       return NULL;
2719     }
2720   }
2721   catch (Standard_Failure& aFail) {
2722     SetErrorCode(aFail.GetMessageString());
2723     return NULL;
2724   }
2725
2726   // BEGIN of fillet
2727   TopoDS_Shape aShapeShape = aShape->GetValue();
2728   TopTools_IndexedMapOfShape anEdgesIndices;
2729   TopExp::MapShapes(aShapeShape, anEdgesIndices);
2730   // Common edges on external cylinders
2731   Handle(GEOM_Object) box_e;
2732   if (theHexMesh) {
2733     box_e = my3DPrimOperations->MakeBoxDXDYDZ(theR2+theW2, theR2+theW2, theR1+theW1);
2734   }
2735   else {
2736     box_e = my3DPrimOperations->MakeBoxDXDYDZ(2*(theR2+theW2), 2*(theR2+theW2), theR1+theW1);
2737   }
2738   box_e->GetLastFunction()->SetDescription("");
2739   box_e = myTransformOperations->TranslateDXDYDZ(box_e, -(theR2+theW2), -(theR2+theW2), 0);
2740   box_e->GetLastFunction()->SetDescription("");
2741
2742   Handle(TColStd_HSequenceOfInteger) edges_e =
2743     myShapesOperations->GetShapesOnBoxIDs(box_e, aShape, TopAbs_EDGE, GEOMAlgo_ST_IN);
2744   box_e->GetLastFunction()->SetDescription("");
2745
2746   if (edges_e.IsNull() || edges_e->Length() == 0) {
2747     SetErrorCode("External edges not found");
2748     return NULL;
2749   }
2750   int nbEdgesInFillet = 0;
2751   std::list<int> theEdges;
2752   for (int i=1; i<=edges_e->Length();i++) {
2753     int edgeID = edges_e->Value(i);
2754     TopoDS_Shape theEdge = anEdgesIndices.FindKey(edgeID);
2755     TopExp_Explorer Ex(theEdge,TopAbs_VERTEX);
2756     while (Ex.More()) {
2757       gp_Pnt aPt = BRep_Tool::Pnt(TopoDS::Vertex(Ex.Current()));
2758       if (Abs(aPt.Z() - (theR1+theW1)) <= Precision::Confusion()) {
2759         nbEdgesInFillet ++;
2760         theEdges.push_back(edgeID);
2761       }
2762       Ex.Next();
2763     }
2764     if (theHexMesh && nbEdgesInFillet == 1)
2765       break;
2766   }
2767
2768   Handle(GEOM_Object) aFillet;
2769   try {
2770     aFillet = myLocalOperations->MakeFilletEdges(aShape, theRF, theEdges);
2771   }
2772   catch (Standard_Failure& aFail) {
2773     SetErrorCode(aFail.GetMessageString());
2774     return NULL;
2775   }
2776   if (aFillet.IsNull()) {
2777     //SetErrorCode("Fillet can not be computed on the given shape with the given parameters");
2778     SetErrorCode(myLocalOperations->GetErrorCode());
2779     return NULL;
2780   }
2781   aFillet->GetLastFunction()->SetDescription("");
2782
2783   TopoDS_Shape aFilletShape = aFillet->GetValue();
2784
2785 #ifdef FILLET_FIX_TOLERANCE
2786   // VSR: 30/12/2014: temporary workaround about Fillet problem
2787   if (theHexMesh) {
2788     GEOMUtils::FixShapeTolerance(aFilletShape, TopAbs_FACE);
2789   }
2790   else {
2791     GEOMUtils::FixShapeCurves(aFilletShape);
2792   }
2793 #endif
2794
2795   aFunction->SetValue(aFilletShape);
2796   // END of fillet
2797
2798 // VSR: debug issues 0021568 and 0021550 (15/05/2012) - BEGIN (1)
2799 // the following block, when enabled, leads to partitioning problems
2800 #if 0
2801 // VSR: debug issues 0021568 and 0021550 (15/05/2012) - END (1)
2802   // BEGIN: Limit tolerances (debug)
2803   Handle(GEOM_Object) aCorr1 = myHealingOperations->LimitTolerance(aShape, 1e-07);
2804   TopoDS_Shape aCorr1Shape = aCorr1->GetValue();
2805   aShape->GetLastFunction()->SetValue(aCorr1Shape);
2806   aCorr1->GetLastFunction()->SetDescription("");
2807   // END: Limit tolerances (debug)
2808 // VSR: debug issues 0021568 and 0021550 (15/05/2012) - BEGIN (2)
2809 #endif
2810 // VSR: debug issues 0021568 and 0021550 (15/05/2012) - END (2)
2811
2812   if (theHexMesh) {
2813     if (!MakePipeTShapePartition(aShape, theR1, theW1, theL1, theR2, theW2, theL2, 0, 0, theRF, false))
2814       return NULL;
2815     if (!MakePipeTShapeMirrorAndGlue(aShape, theR1, theW1, theL1, theR2, theW2, theL2))
2816       return NULL;
2817   }
2818
2819   // Add thickness reduction elements
2820   // at the three extremities: Left, Right and Incident
2821   try {
2822     OCC_CATCH_SIGNALS;
2823     if (isTRL || isTRR || isTRI) {
2824       TopoDS_Shape aResShape =
2825         MakePipeTShapeThicknessReduction(aShape->GetValue(), theR1, theW1, theL1, theR2, theW2, theL2,
2826                                          theRL, theWL, theLtransL, theLthinL,
2827                                          theRR, theWR, theLtransR, theLthinR,
2828                                          theRI, theWI, theLtransI, theLthinI,
2829                                          !theHexMesh);
2830       aFunction->SetValue(aResShape);
2831     }
2832   }
2833   catch (Standard_Failure& aFail) {
2834     SetErrorCode(aFail.GetMessageString());
2835     return NULL;
2836   }
2837
2838   Handle(TColStd_HSequenceOfTransient) aSeq = new TColStd_HSequenceOfTransient;
2839   aSeq->Append(aShape);
2840
2841   try {
2842     if (theHexMesh) {
2843       // Get the groups
2844       if (!MakeGroups(aShape, TSHAPE_FILLET, theR1, theW1, theL1, theR2, theW2, theL2,
2845                       0., 0., theRF, aSeq, gp_Trsf()))
2846         return NULL;
2847     }
2848
2849     // Get internal group.
2850     if (!MakeInternalGroup(aShape, theR1, theL1, theR2, theL2, theRL, theLtransL,
2851                            theRR, theLtransR, theRI, theLtransI,
2852                            aSeq, gp_Trsf())) {
2853       return NULL;
2854     }
2855   }
2856   catch (Standard_Failure& aFail) {
2857     SetErrorCode(aFail.GetMessageString());
2858     return NULL;
2859   }
2860
2861   //Make a Python command
2862   TCollection_AsciiString anEntry, aListRes("[");
2863   // Iterate over the sequence aSeq
2864   Standard_Integer aNbGroups = aSeq->Length();
2865   Standard_Integer i = 1;
2866   for (; i <= aNbGroups; i++) {
2867     Handle(Standard_Transient) anItem = aSeq->Value(i);
2868     if (anItem.IsNull()) continue;
2869     Handle(GEOM_Object) aGroup = Handle(GEOM_Object)::DownCast(anItem);
2870     if (aGroup.IsNull()) continue;
2871     //Make a Python command
2872     TDF_Tool::Entry(aGroup->GetEntry(), anEntry);
2873     aListRes += anEntry + ", ";
2874   }
2875   aListRes.Trunc(aListRes.Length() - 2);
2876
2877   GEOM::TPythonDump pd (aFunction);
2878
2879   pd << aListRes.ToCString() << "] = geompy.MakePipeTShapeFillet("
2880      << theR1 << ", " << theW1 << ", " << theL1 << ", "
2881      << theR2 << ", " << theW2 << ", " << theL2 << ", "
2882      << theRF << ", " << theHexMesh;
2883
2884   // thickness reduction
2885   if (isTRL)
2886     pd << ", theRL=" << theRL << ", theWL=" << theWL
2887        << ", theLtransL=" << theLtransL << ", theLthinL=" << theLthinL;
2888   if (isTRR)
2889     pd << ", theRR=" << theRR << ", theWR=" << theWR
2890        << ", theLtransR=" << theLtransR << ", theLthinR=" << theLthinR;
2891   if (isTRI)
2892     pd << ", theRI=" << theRI << ", theWI=" << theWI
2893        << ", theLtransI=" << theLtransI << ", theLthinI=" << theLthinI;
2894
2895   pd << ")";
2896
2897   SetErrorCode(OK);
2898
2899   return aSeq;
2900 }
2901
2902 //=============================================================================
2903 /*!
2904  *  MakePipeTShapeFilletWithPosition
2905  *  \brief Create a T-shape object with specified caracteristics for the main and
2906  *  the incident pipes (radius, width, half-length). A fillet is created
2907  *  on the junction of the pipes.
2908  *  The extremities of the main pipe are located on junctions points P1 and P2.
2909  *  The extremity of the incident pipe is located on junction point P3.
2910  *  \param theR1 Internal radius of main pipe
2911  *  \param theW1 Width of main pipe
2912  *  \param theL1 Half-length of main pipe
2913  *  \param theR2 Internal radius of incident pipe (R2 < R1)
2914  *  \param theW2 Width of incident pipe (R2+W2 < R1+W1)
2915  *  \param theL2 Half-length of incident pipe
2916  *  \param theRF Radius of curvature of fillet
2917  *  \param theHexMesh Boolean indicating if shape is prepared for hex mesh
2918  *  \param theP1 1st junction point of main pipe
2919  *  \param theP2 2nd junction point of main pipe
2920  *  \param theP3 Junction point of incident pipe
2921  *  \return List of GEOM_Objects, containing the created shape and propagation groups.
2922  */
2923 //=============================================================================
2924 Handle(TColStd_HSequenceOfTransient)
2925 AdvancedEngine_IOperations::MakePipeTShapeFilletWithPosition
2926                              (double theR1, double theW1, double theL1,
2927                               double theR2, double theW2, double theL2,
2928                               double theRL, double theWL, double theLtransL, double theLthinL,
2929                               double theRR, double theWR, double theLtransR, double theLthinR,
2930                               double theRI, double theWI, double theLtransI, double theLthinI,
2931                               double theRF, bool theHexMesh,
2932                               Handle(GEOM_Object) theP1,
2933                               Handle(GEOM_Object) theP2,
2934                               Handle(GEOM_Object) theP3)
2935 {
2936   SetErrorCode(KO);
2937   //Add a new object
2938   Handle(GEOM_Object) aShape = GetEngine()->AddObject(GEOM_TSHAPE);
2939   //Add a new shape function with parameters
2940   Handle(GEOM_Function) aFunction = aShape->AddFunction(AdvancedEngine_PipeTShapeDriver::GetID(), TSHAPE_FILLET);
2941   if (aFunction.IsNull()) return NULL;
2942
2943   //Check if the function is set correctly
2944   if (aFunction->GetDriverGUID() != AdvancedEngine_PipeTShapeDriver::GetID()) return NULL;
2945
2946   // Check new position
2947   if (!CheckCompatiblePosition(theL1, theL2, theP1, theP2, theP3, 0.01)) {
2948     return NULL;
2949   }
2950
2951   AdvancedEngine_IPipeTShape aData(aFunction);
2952
2953   aData.SetR1(theR1);
2954   aData.SetW1(theW1);
2955   aData.SetL1(theL1);
2956   aData.SetR2(theR2);
2957   aData.SetW2(theW2);
2958   aData.SetL2(theL2);
2959   aData.SetRF(theRF);
2960   aData.SetHexMesh(theHexMesh);
2961
2962   bool isTRL = (theRL + theWL + theLtransL + theLthinL) > Precision::Confusion();
2963   bool isTRR = (theRR + theWR + theLtransR + theLthinR) > Precision::Confusion();
2964   bool isTRI = (theRI + theWI + theLtransI + theLthinI) > Precision::Confusion();
2965
2966   //Compute the resulting value
2967   try {
2968     OCC_CATCH_SIGNALS;
2969     if (!GetSolver()->ComputeFunction(aFunction)) {
2970       SetErrorCode("TShape driver failed");
2971       return NULL;
2972     }
2973   }
2974   catch (Standard_Failure& aFail) {
2975     SetErrorCode(aFail.GetMessageString());
2976     return NULL;
2977   }
2978
2979   // BEGIN of fillet
2980   TopoDS_Shape aShapeShape = aShape->GetValue();
2981   TopTools_IndexedMapOfShape anEdgesIndices;
2982   TopExp::MapShapes(aShapeShape, anEdgesIndices);
2983   // Common edges on external cylinders
2984   Handle(GEOM_Object) box_e;
2985   if (theHexMesh) {
2986     box_e = my3DPrimOperations->MakeBoxDXDYDZ(theR2+theW2, theR2+theW2, theR1+theW1);
2987   }
2988   else {
2989     box_e = my3DPrimOperations->MakeBoxDXDYDZ(2*(theR2+theW2), 2*(theR2+theW2), theR1+theW1);
2990   }
2991   box_e->GetLastFunction()->SetDescription("");
2992   box_e = myTransformOperations->TranslateDXDYDZ(box_e, -(theR2+theW2), -(theR2+theW2), 0);
2993   box_e->GetLastFunction()->SetDescription("");
2994
2995   Handle(TColStd_HSequenceOfInteger) edges_e =
2996     myShapesOperations->GetShapesOnBoxIDs(box_e, aShape, TopAbs_EDGE, GEOMAlgo_ST_IN);
2997   box_e->GetLastFunction()->SetDescription("");
2998
2999   if (edges_e.IsNull() || edges_e->Length() == 0) {
3000     SetErrorCode("External edges not found");
3001     return NULL;
3002   }
3003   int nbEdgesInFillet = 0;
3004   std::list<int> theEdges;
3005   for (int i=1; i<=edges_e->Length();i++) {
3006     int edgeID = edges_e->Value(i);
3007     TopoDS_Shape theEdge = anEdgesIndices.FindKey(edgeID);
3008     TopExp_Explorer Ex(theEdge,TopAbs_VERTEX);
3009     while (Ex.More()) {
3010       gp_Pnt aPt = BRep_Tool::Pnt(TopoDS::Vertex(Ex.Current()));
3011       if (Abs(aPt.Z() - (theR1+theW1)) <= Precision::Confusion()) {
3012         nbEdgesInFillet ++;
3013         theEdges.push_back(edgeID);
3014       }
3015       Ex.Next();
3016     }
3017     if (theHexMesh && nbEdgesInFillet == 1)
3018       break;
3019   }
3020
3021   Handle(GEOM_Object) aFillet;
3022   try {
3023     aFillet = myLocalOperations->MakeFilletEdges(aShape, theRF, theEdges);
3024   }
3025   catch (Standard_Failure& aFail) {
3026     SetErrorCode(aFail.GetMessageString());
3027     return NULL;
3028   }
3029   if (aFillet.IsNull()) {
3030     SetErrorCode("Fillet can not be computed on the given shape with the given parameters");
3031     return NULL;
3032   }
3033   aFillet->GetLastFunction()->SetDescription("");
3034
3035   TopoDS_Shape aFilletShape = aFillet->GetValue();
3036
3037 #ifdef FILLET_FIX_TOLERANCE
3038   // VSR: 30/12/2014: temporary workaround about Fillet problem
3039   if (theHexMesh) {
3040     GEOMUtils::FixShapeTolerance(aFilletShape, TopAbs_FACE);
3041   }
3042   else {
3043     GEOMUtils::FixShapeCurves(aFilletShape);
3044   }
3045 #endif
3046
3047   aFunction->SetValue(aFilletShape);
3048   // END of fillet
3049
3050 // VSR: debug issues 0021568 and 0021550 (15/05/2012) - BEGIN (3)
3051 // the following block, when enabled, leads to partitioning problems
3052 #if 0
3053 // VSR: debug issues 0021568 and 0021550 (15/05/2012) - END (3)
3054   // BEGIN: Limit tolerances (debug)
3055   Handle(GEOM_Object) aCorr1 = myHealingOperations->LimitTolerance(aShape, 1e-07);
3056   TopoDS_Shape aCorr1Shape = aCorr1->GetValue();
3057   aShape->GetLastFunction()->SetValue(aCorr1Shape);
3058   aCorr1->GetLastFunction()->SetDescription("");
3059   // END: Limit tolerances (debug)
3060 // VSR: debug issues 0021568 and 0021550 (15/05/2012) - BEGIN (4)
3061 #endif
3062 // VSR: debug issues 0021568 and 0021550 (15/05/2012) - END (4)
3063
3064   if (theHexMesh) {
3065     if (!MakePipeTShapePartition(aShape, theR1, theW1, theL1, theR2, theW2, theL2, 0, 0, theRF, false))
3066       return NULL;
3067     if (!MakePipeTShapeMirrorAndGlue(aShape, theR1, theW1, theL1, theR2, theW2, theL2))
3068       return NULL;
3069   }
3070
3071   // Add thickness reduction elements
3072   // at the three extremities: Left, Right and Incident
3073   try {
3074     OCC_CATCH_SIGNALS;
3075     if (isTRL || isTRR || isTRI) {
3076       TopoDS_Shape aResShape =
3077         MakePipeTShapeThicknessReduction(aShape->GetValue(), theR1, theW1, theL1, theR2, theW2, theL2,
3078                                          theRL, theWL, theLtransL, theLthinL,
3079                                          theRR, theWR, theLtransR, theLthinR,
3080                                          theRI, theWI, theLtransI, theLthinI,
3081                                          !theHexMesh);
3082       aFunction->SetValue(aResShape);
3083     }
3084   }
3085   catch (Standard_Failure& aFail) {
3086     SetErrorCode(aFail.GetMessageString());
3087     return NULL;
3088   }
3089
3090   // Set Position
3091   gp_Trsf aTrsf = GetPositionTrsf(theL1, theL2, theP1, theP2, theP3);
3092   BRepBuilderAPI_Transform aTransformation (aShape->GetValue(), aTrsf, Standard_False);
3093   TopoDS_Shape aTrsf_Shape = aTransformation.Shape();
3094   aFunction->SetValue(aTrsf_Shape);
3095
3096   Handle(TColStd_HSequenceOfTransient) aSeq = new TColStd_HSequenceOfTransient;
3097   aSeq->Append(aShape);
3098
3099   try {
3100     if (theHexMesh) {
3101       // Get the groups
3102       if (!MakeGroups(aShape, TSHAPE_FILLET, theR1, theW1, theL1, theR2, theW2, theL2,
3103                       0., 0., theRF, aSeq, aTrsf))
3104         return NULL;
3105     }
3106
3107     // Get internal group.
3108     if (!MakeInternalGroup(aShape, theR1, theL1, theR2, theL2, theRL, theLtransL,
3109                            theRR, theLtransR, theRI, theLtransI,
3110                            aSeq, aTrsf)) {
3111       return NULL;
3112     }
3113   }
3114   catch (Standard_Failure& aFail) {
3115     SetErrorCode(aFail.GetMessageString());
3116     return NULL;
3117   }
3118
3119   //Make a Python command
3120   TCollection_AsciiString anEntry, aListRes("[");
3121   // Iterate over the sequence aSeq
3122   Standard_Integer aNbGroups = aSeq->Length();
3123   Standard_Integer i = 1;
3124   for (; i <= aNbGroups; i++) {
3125     Handle(Standard_Transient) anItem = aSeq->Value(i);
3126     if (anItem.IsNull()) continue;
3127     Handle(GEOM_Object) aGroup = Handle(GEOM_Object)::DownCast(anItem);
3128     if (aGroup.IsNull()) continue;
3129     //Make a Python command
3130     TDF_Tool::Entry(aGroup->GetEntry(), anEntry);
3131     aListRes += anEntry + ", ";
3132   }
3133   aListRes.Trunc(aListRes.Length() - 2);
3134
3135   GEOM::TPythonDump pd (aFunction);
3136
3137   pd << aListRes.ToCString() << "] = geompy.MakePipeTShapeFillet("
3138      << theR1 << ", " << theW1 << ", " << theL1 << ", "
3139      << theR2  << ", " << theW2 << ", " << theL2 << ", "
3140      << theRF << ", " << theHexMesh << ", "
3141      << theP1 << ", " << theP2 << ", " << theP3;
3142
3143   // thickness reduction
3144   if (isTRL)
3145     pd << ", theRL=" << theRL << ", theWL=" << theWL
3146        << ", theLtransL=" << theLtransL << ", theLthinL=" << theLthinL;
3147   if (isTRR)
3148     pd << ", theRR=" << theRR << ", theWR=" << theWR
3149        << ", theLtransR=" << theLtransR << ", theLthinR=" << theLthinR;
3150   if (isTRI)
3151     pd << ", theRI=" << theRI << ", theWI=" << theWI
3152        << ", theLtransI=" << theLtransI << ", theLthinI=" << theLthinI;
3153
3154   pd << ")";
3155
3156   SetErrorCode(OK);
3157
3158   return aSeq;
3159 }
3160
3161 //=============================================================================
3162 /*!
3163  *  This function allows to create a disk already divided into blocks. It can be
3164  *  used to create divided pipes for later meshing in hexaedra.
3165  *  \param theR Radius of the disk
3166  *  \param theRatio Relative size of the central square diagonal against the disk diameter
3167  *  \param theOrientation Plane on which the disk will be built
3168  *  \param thePattern The division pattern of the disk (hexagon or square in the center)
3169  *  \return New GEOM_Object, containing the created shape.
3170  */
3171 //=============================================================================
3172 Handle(GEOM_Object) AdvancedEngine_IOperations::MakeDividedDisk (double theR, double theRatio, 
3173                                                                  int theOrientation, int thePattern)
3174 {
3175   SetErrorCode(KO);
3176   
3177   if (theOrientation != 1 &&
3178       theOrientation != 2 &&
3179       theOrientation != 3)
3180   {
3181     SetErrorCode("theOrientation must be 1(=OXY), 2(=OYZ) or 3(=OZX)");
3182     return NULL;
3183   }
3184   //Add a new object
3185   Handle(GEOM_Object) aShape = GetEngine()->AddObject(GEOM_DIVIDEDDISK);
3186
3187   //Add a new shape function with parameters
3188   Handle(GEOM_Function) aFunction = aShape->AddFunction(AdvancedEngine_DividedDiskDriver::GetID(), DIVIDEDDISK_R_RATIO);
3189   if (aFunction.IsNull()) return NULL;
3190
3191   //Check if the function is set correctly
3192   if (aFunction->GetDriverGUID() != AdvancedEngine_DividedDiskDriver::GetID()) return NULL;
3193
3194   AdvancedEngine_IDividedDisk aData (aFunction);
3195
3196   aData.SetR(theR);
3197   aData.SetRatio(theRatio);
3198   aData.SetOrientation(theOrientation);
3199   aData.SetType(thePattern);
3200
3201   //Compute the resulting value
3202   try {
3203     OCC_CATCH_SIGNALS;
3204     if (!GetSolver()->ComputeFunction(aFunction)) {
3205       SetErrorCode("DividedDisk driver failed");
3206       return NULL;
3207     }
3208   }
3209   catch (Standard_Failure& aFail) {
3210     SetErrorCode(aFail.GetMessageString());
3211     return NULL;
3212   }
3213   
3214   std::string aPatternStr;
3215   
3216   switch(thePattern)
3217   {
3218     case 0:
3219       aPatternStr = "GEOM.SQUARE";
3220       break;
3221     case 1:
3222       aPatternStr = "GEOM.HEXAGON";
3223       break;
3224   }
3225   
3226   //Make a Python command
3227   GEOM::TPythonDump(aFunction) << aShape << " = geompy.MakeDividedDisk(" << theR << ", " << theOrientation << ", " << aPatternStr.c_str() << ")";
3228
3229   SetErrorCode(OK);
3230
3231   return aShape;
3232 }
3233
3234 //=============================================================================
3235 /*!
3236  *  This function allows to create a disk already divided into blocks. It can be
3237  *  used to create divided pipes for later meshing in hexaedra.
3238  *  \param theR Radius of the disk
3239  *  \param theRatio Relative size of the central square diagonal against the disk diameter
3240  *  \return New GEOM_Object, containing the created shape.
3241  */
3242 //=============================================================================
3243 Handle(GEOM_Object) AdvancedEngine_IOperations::MakeDividedDiskPntVecR (Handle(GEOM_Object) thePnt, 
3244                                                                         Handle(GEOM_Object) theVec, 
3245                                                                         double theR, 
3246                                                                         double theRatio,
3247                                                                         int    thePattern)
3248 {
3249   SetErrorCode(KO);
3250
3251   //Add a new object
3252   Handle(GEOM_Object) aShape = GetEngine()->AddObject(GEOM_DIVIDEDDISK);
3253
3254   //Add a new shape function with parameters
3255   Handle(GEOM_Function) aFunction = aShape->AddFunction(AdvancedEngine_DividedDiskDriver::GetID(), DIVIDEDDISK_R_VECTOR_PNT);
3256   if (aFunction.IsNull()) return NULL;
3257
3258   //Check if the function is set correctly
3259   if (aFunction->GetDriverGUID() != AdvancedEngine_DividedDiskDriver::GetID()) return NULL;
3260
3261   AdvancedEngine_IDividedDisk aData (aFunction);
3262   
3263   Handle(GEOM_Function) aRefPnt = thePnt->GetLastFunction();
3264   Handle(GEOM_Function) aRefVec = theVec->GetLastFunction();
3265
3266   if (aRefPnt.IsNull() || aRefVec.IsNull()) return NULL;
3267
3268   aData.SetCenter(aRefPnt);
3269   aData.SetVector(aRefVec);
3270
3271   aData.SetR(theR);
3272   aData.SetRatio(theRatio);
3273   aData.SetType(thePattern);
3274
3275   //Compute the resulting value
3276   try {
3277     OCC_CATCH_SIGNALS;
3278     if (!GetSolver()->ComputeFunction(aFunction)) {
3279       SetErrorCode("DividedDisk driver failed");
3280       return NULL;
3281     }
3282   }
3283   catch (Standard_Failure& aFail) {
3284     SetErrorCode(aFail.GetMessageString());
3285     return NULL;
3286   }
3287   
3288   std::string aPatternStr;
3289   
3290   switch(thePattern)
3291   {
3292     case 0:
3293       aPatternStr = "GEOM.SQUARE";
3294       break;
3295     case 1:
3296       aPatternStr = "GEOM.HEXAGON";
3297       break;
3298   }
3299   
3300
3301   //Make a Python command
3302   GEOM::TPythonDump(aFunction) << aShape << " = geompy.MakeDividedDiskPntVecR(" << thePnt << ", " << theVec << ", " << theR << ", " << aPatternStr.c_str() << ")";
3303
3304   SetErrorCode(OK);
3305
3306   return aShape;
3307 }
3308
3309 //=============================================================================
3310 /*!
3311  *  Builds a cylinder prepared for hexa meshes
3312  *  \param theR Radius of the cylinder
3313  *  \param theH Height of the cylinder
3314  *  \return New GEOM_Object, containing the created shape.
3315  */
3316 //=============================================================================
3317 Handle(GEOM_Object) AdvancedEngine_IOperations::MakeDividedCylinder (double theR, 
3318                                                                      double theH,
3319                                                                      int    thePattern)
3320 {
3321   SetErrorCode(KO);
3322   
3323   //Add a new object
3324   Handle(GEOM_Object) aShape = GetEngine()->AddObject(GEOM_DIVIDEDCYLINDER);
3325
3326   Handle(GEOM_Object) aBaseShape = MakeDividedDisk(theR, 67.0, 1, thePattern);
3327   aBaseShape->GetLastFunction()->SetDescription("");   // Erase dump of MakeDividedDisk
3328   
3329   aShape = my3DPrimOperations->MakePrismDXDYDZ(aBaseShape,0.0,0.0,theH, -1.0);
3330         
3331   Handle(GEOM_Function) aFunction =  aShape->GetLastFunction();
3332   aFunction->SetDescription("");   // Erase dump of MakePrismDXDYDZ
3333   aShape->SetType(GEOM_DIVIDEDCYLINDER);
3334   
3335   std::string aPatternStr;
3336   
3337   switch(thePattern)
3338   {
3339     case 0:
3340       aPatternStr = "GEOM.SQUARE";
3341       break;
3342     case 1:
3343       aPatternStr = "GEOM.HEXAGON";
3344       break;
3345   }
3346   
3347   //Make a Python command
3348   GEOM::TPythonDump(aFunction) << aShape << " = geompy.MakeDividedCylinder(" << theR << ", " << theH << ", " << aPatternStr.c_str() << ")";
3349
3350   SetErrorCode(OK);
3351
3352   return aShape;
3353 }
3354 //=============================================================================
3355 /*!
3356  *  Create a smoothing surface from a set of points
3357  *  \param thelPoints list of points or compounds of points
3358  *  \param theNbMax maximum number of Bezier pieces in the resulting surface.
3359  *  \param theDegMax maximum degree of the resulting BSpline surface
3360  *  \param theDMax specifies maximum value of the GeomPlate_PlateG0Criterion criterion.
3361  *  \return New GEOM_Object, containing the created shape.
3362  */
3363 //=============================================================================
3364 Handle(GEOM_Object) AdvancedEngine_IOperations::MakeSmoothingSurface (std::list<Handle(GEOM_Object)> thelPoints, 
3365                                                                       int                            theNbMax,
3366                                                                       int                            theDegMax,
3367                                                                       double                         theDMax)
3368 {
3369   SetErrorCode(KO);
3370
3371   //Add a new object
3372   Handle(GEOM_Object) aShape = GetEngine()->AddObject(GEOM_SMOOTHINGSURFACE);
3373
3374   //Add a new shape function with parameters
3375   Handle(GEOM_Function) aFunction = aShape->AddFunction(AdvancedEngine_SmoothingSurfaceDriver::GetID(), SMOOTHINGSURFACE_LPOINTS);
3376   if (aFunction.IsNull()) return NULL;
3377
3378   //Check if the function is set correctly
3379   if (aFunction->GetDriverGUID() != AdvancedEngine_SmoothingSurfaceDriver::GetID()) return NULL;
3380
3381   AdvancedEngine_ISmoothingSurface aData (aFunction);
3382
3383   int aLen = thelPoints.size();
3384   aData.SetLength(aLen);
3385   int ind = 1;
3386   std::list<Handle(GEOM_Object)>::iterator it = thelPoints.begin();
3387   for (; it != thelPoints.end(); it++, ind++) {
3388     Handle(GEOM_Function) aRefObj = (*it)->GetLastFunction();
3389     if (aRefObj.IsNull()) {
3390       SetErrorCode("NULL point or compound for bSplineFaceShape");
3391       return NULL;
3392     }
3393     aData.SetPntOrComp(ind, aRefObj);
3394   }
3395
3396   aData.SetNbMax(theNbMax);
3397   aData.SetDegMax(theDegMax);
3398   aData.SetDMax(theDMax);
3399
3400   //Compute the resulting value
3401   try {
3402     OCC_CATCH_SIGNALS;
3403     if (!GetSolver()->ComputeFunction(aFunction)) {
3404       SetErrorCode("SmoothingSurface driver failed");
3405       return NULL;
3406     }
3407   }
3408   catch (Standard_Failure& aFail) {
3409     SetErrorCode(aFail.GetMessageString());
3410     return NULL;
3411   }
3412
3413   //Make a Python command
3414   GEOM::TPythonDump pd (aFunction);
3415   pd << aShape << " = geompy.MakeSmoothingSurface([";
3416   it = thelPoints.begin();
3417   pd << (*it++);
3418   while (it != thelPoints.end()) {
3419     pd << ", " << (*it++);
3420   }
3421   pd << "], "
3422      << theNbMax << ", "
3423      << theDegMax << ", "
3424      << theDMax <<")";
3425
3426   SetErrorCode(OK);
3427
3428   return aShape;
3429 }