Salome HOME
9a86c59fe1eb4e5b44d9ef32831932ad031b5f59
[modules/geom.git] / src / GEOMImpl / GEOMImpl_IAdvancedOperations.cxx
1 //  Copyright (C) 2007-2010  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.
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   : GEOMImpl_IAdvancedOperations.cxx
20 //  Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com)
21
22 #include <Standard_Stream.hxx>
23 #include "GEOMImpl_Types.hxx"
24 #include "GEOMImpl_IAdvancedOperations.hxx"
25 #include "GEOMImpl_IBasicOperations.hxx"
26 #include "GEOMImpl_IBooleanOperations.hxx"
27 #include "GEOMImpl_IShapesOperations.hxx"
28 #include "GEOMImpl_ITransformOperations.hxx"
29 #include "GEOMImpl_IBlocksOperations.hxx"
30 #include "GEOMImpl_I3DPrimOperations.hxx"
31 #include "GEOMImpl_ILocalOperations.hxx"
32 #include "GEOMImpl_IHealingOperations.hxx"
33
34 #include "GEOMImpl_Gen.hxx"
35
36 #include <utilities.h>
37 #include <OpUtil.hxx>
38 #include <Utils_ExceptHandlers.hxx>
39
40 #include "GEOM_Function.hxx"
41 #include "GEOM_PythonDump.hxx"
42
43 #include "GEOMImpl_PipeTShapeDriver.hxx"
44 #include "GEOMImpl_IPipeTShape.hxx"
45 /*@@ insert new functions before this line @@ do not remove this line @@ do not remove this line @@*/
46
47 #include <TopExp.hxx>
48 #include <TopExp_Explorer.hxx>
49 #include <TopoDS.hxx>
50 #include <TopoDS_Vertex.hxx>
51 #include <TopTools_IndexedMapOfShape.hxx>
52
53 #include <gp_Pnt.hxx>
54 #include <gp_Vec.hxx>
55 #include <gp_Ax3.hxx>
56 #include <BRepBuilderAPI_Transform.hxx>
57 #include <BRep_Tool.hxx>
58 #include <cmath>
59
60 #include <TFunction_DriverTable.hxx>
61 #include <TFunction_Driver.hxx>
62 #include <TFunction_Logbook.hxx>
63 #include <TDF_Tool.hxx>
64 #include <Standard_Failure.hxx>
65 #include <Standard_ErrorHandler.hxx> // CAREFUL ! position of this file is critic : see Lucien PIGNOLONI / OCC
66
67 #define HALF_LENGTH_MAIN_PIPE     "Main pipe half length" //"Tuyau principal - demi longueur"
68 #define HALF_LENGTH_INCIDENT_PIPE "Incident pipe half length" //"Tuyau incident - demi longueur"
69 #define CIRCULAR_QUARTER_PIPE     "Circular quarter of pipe" //"Circulaire - quart de tuyau"
70 #define THICKNESS                 "Thickness" //"Epaisseur"
71 #define FLANGE                    "Flange" // "Collerette"
72 #define CHAMFER_OR_FILLET         "Chamfer or fillet" //"Chanfrein ou Raccord"
73 #define JUNCTION_FACE_1           "Junction 1" //"Face de jonction 1"
74 #define JUNCTION_FACE_2           "Junction 2" //"Face de jonction 2"
75 #define JUNCTION_FACE_3           "Junction 3" //"Face de jonction 3"
76
77 //=============================================================================
78 /*!
79  *  Constructor
80  */
81 //=============================================================================
82 GEOMImpl_IAdvancedOperations::GEOMImpl_IAdvancedOperations(GEOM_Engine* theEngine, int theDocID) :
83   GEOM_IOperations(theEngine, theDocID)
84 {
85   MESSAGE("GEOMImpl_IAdvancedOperations::GEOMImpl_IAdvancedOperations");
86   myBasicOperations     = new GEOMImpl_IBasicOperations(GetEngine(), GetDocID());
87   myBooleanOperations   = new GEOMImpl_IBooleanOperations(GetEngine(), GetDocID());
88   myShapesOperations    = new GEOMImpl_IShapesOperations(GetEngine(), GetDocID());
89   myTransformOperations = new GEOMImpl_ITransformOperations(GetEngine(), GetDocID());
90   myBlocksOperations    = new GEOMImpl_IBlocksOperations(GetEngine(), GetDocID());
91   my3DPrimOperations    = new GEOMImpl_I3DPrimOperations(GetEngine(), GetDocID());
92   myLocalOperations     = new GEOMImpl_ILocalOperations(GetEngine(), GetDocID());
93   myHealingOperations   = new GEOMImpl_IHealingOperations(GetEngine(), GetDocID());
94 }
95
96 //=============================================================================
97 /*!
98  *  Destructor
99  */
100 //=============================================================================
101 GEOMImpl_IAdvancedOperations::~GEOMImpl_IAdvancedOperations()
102 {
103   MESSAGE("GEOMImpl_IAdvancedOperations::~GEOMImpl_IAdvancedOperations");
104   delete myBasicOperations;
105   delete myBooleanOperations;
106   delete myShapesOperations;
107   delete myTransformOperations;
108   delete myBlocksOperations;
109   delete my3DPrimOperations;
110   delete myLocalOperations;
111   delete myHealingOperations;
112 }
113
114 //=============================================================================
115 /*!
116  *  SetPosition
117  */
118 //=============================================================================
119 gp_Trsf GEOMImpl_IAdvancedOperations::GetPositionTrsf(double theL1, double theL2,
120                                                       Handle(GEOM_Object) theP1,
121                                                       Handle(GEOM_Object) theP2,
122                                                       Handle(GEOM_Object) theP3)
123 {
124   // Old Local Coordinates System oldLCS
125   gp_Pnt P0(0, 0, 0);
126   gp_Pnt P1(-theL1, 0, 0);
127   gp_Pnt P2(theL1, 0, 0);
128   gp_Pnt P3(0, 0, theL2);
129
130   gp_Dir oldX(gp_Vec(P1, P2));
131   gp_Dir oldZ(gp_Vec(P0, P3));
132   gp_Ax3 oldLCS(P0, oldZ, oldX);
133
134   // New Local Coordinates System newLCS
135   double LocX, LocY, LocZ;
136   gp_Pnt newP1 = BRep_Tool::Pnt(TopoDS::Vertex(theP1->GetValue()));
137   gp_Pnt newP2 = BRep_Tool::Pnt(TopoDS::Vertex(theP2->GetValue()));
138   gp_Pnt newP3 = BRep_Tool::Pnt(TopoDS::Vertex(theP3->GetValue()));
139   LocX = (newP1.X() + newP2.X()) / 2.;
140   LocY = (newP1.Y() + newP2.Y()) / 2.;
141   LocZ = (newP1.Z() + newP2.Z()) / 2.;
142   gp_Pnt newO(LocX, LocY, LocZ);
143
144   gp_Dir newX(gp_Vec(newP1, newP2)); // P1P2 Vector
145   gp_Dir newZ(gp_Vec(newO, newP3)); // OP3 Vector
146   gp_Ax3 newLCS = gp_Ax3(newO, newZ, newX);
147
148   gp_Trsf aTrsf;
149   aTrsf.SetDisplacement(oldLCS, newLCS);
150
151   return aTrsf;
152 }
153
154 //=============================================================================
155 /*!
156  *  CheckCompatiblePosition
157  *
158  */
159 //=============================================================================
160 bool GEOMImpl_IAdvancedOperations::CheckCompatiblePosition(double& theL1, double& theL2,
161                                                            Handle(GEOM_Object) theP1,
162                                                            Handle(GEOM_Object) theP2,
163                                                            Handle(GEOM_Object) theP3,
164                                                            double theTolerance)
165 {
166   SetErrorCode(KO);
167   gp_Pnt P1 = BRep_Tool::Pnt(TopoDS::Vertex(theP1->GetValue()));
168   gp_Pnt P2 = BRep_Tool::Pnt(TopoDS::Vertex(theP2->GetValue()));
169   gp_Pnt P3 = BRep_Tool::Pnt(TopoDS::Vertex(theP3->GetValue()));
170
171   double d12 = P1.Distance(P2);
172   double d13 = P1.Distance(P3);
173   double d23 = P2.Distance(P3);
174   //    double d2 = newO.Distance(P3);
175
176   if (Abs(d12) <= Precision::Confusion()) {
177     SetErrorCode("Junctions points P1 and P2 are identical");
178     return false;
179   }
180   if (Abs(d13) <= Precision::Confusion()) {
181     SetErrorCode("Junctions points P1 and P3 are identical");
182     return false;
183   }
184   if (Abs(d23) <= Precision::Confusion()) {
185     SetErrorCode("Junctions points P2 and P3 are identical");
186     return false;
187   }
188
189
190   double newL1 = 0.5 * d12;
191   double newL2 = sqrt(pow(d13,2)-pow(newL1,2));
192   //
193   // theL1*(1-theTolerance) <= newL1 <= theL1*(1+theTolerance)
194   //
195   if (fabs(newL1 - theL1) > Precision::Approximation()) {
196     if ( (newL1 * (1 - theTolerance) -theL1 <= Precision::Approximation()) &&
197          (newL1 * (1 + theTolerance) -theL1 >= Precision::Approximation()) ) {
198       //            std::cerr << "theL1 = newL1" << std::endl;
199       theL1 = newL1;
200     } else {
201       theL1 = -1;
202       SetErrorCode("Dimension for main pipe (L1) is incompatible with new position");
203       return false;
204     }
205   }
206
207   //
208   // theL2*(1-theTolerance) <= newL2  <= theL2*(1+theTolerance)
209   //
210   if (fabs(newL2 - theL2) > Precision::Approximation()) {
211     if ( (newL2 * (1 - theTolerance) -theL2 <= Precision::Approximation()) &&
212          (newL2 * (1 + theTolerance) -theL2 >= Precision::Approximation()) ) {
213       theL2 = newL2;
214     } else {
215       theL2 = -1;
216       SetErrorCode("Dimension for incident pipe (L2) is incompatible with new position");
217       return false;
218     }
219   }
220
221   SetErrorCode(OK);
222   return true;
223
224 }
225
226 //=============================================================================
227 /*!
228  *  Generate the propagation groups of a Pipe T-Shape used for hexa mesh
229  */
230 //=============================================================================
231 bool GEOMImpl_IAdvancedOperations::MakeGroups(Handle(GEOM_Object) theShape, int shapeType,
232                                               double theR1, double theW1, double theL1,
233                                               double theR2, double theW2, double theL2,
234                                               Handle(TColStd_HSequenceOfTransient) theSeq,
235                                               gp_Trsf aTrsf)
236 {
237   SetErrorCode(KO);
238
239   if (theShape.IsNull()) return false;
240
241   TopoDS_Shape aShape = theShape->GetValue();
242   if (aShape.IsNull()) {
243     SetErrorCode("Shape is not defined");
244     return false;
245   }
246
247   gp_Trsf aTrsfInv = aTrsf.Inverted();
248
249   int expectedGroups = 0;
250   if (shapeType == TSHAPE_BASIC)
251     if (Abs(theR2+theW2-theR1-theW1) <= Precision::Approximation())
252       expectedGroups = 10;
253     else
254       expectedGroups = 11;
255   else if (shapeType == TSHAPE_CHAMFER || shapeType == TSHAPE_FILLET)
256     expectedGroups = 12;
257
258   double aR1Ext = theR1 + theW1;
259   double aR2Ext = theR2 + theW2;
260
261   /////////////////////////
262   //// Groups of Faces ////
263   /////////////////////////
264
265   //
266   // Comment the following lines when GetInPlace bug is solved
267   // == BEGIN
268   // Workaround of GetInPlace bug
269   // Create a bounding box that fits the shape
270   Handle(GEOM_Object) aBox = my3DPrimOperations->MakeBoxDXDYDZ(2*theL1, 2*aR1Ext, aR1Ext+theL2);
271   aBox->GetLastFunction()->SetDescription("");
272   myTransformOperations->TranslateDXDYDZ(aBox, -theL1, -aR1Ext, -aR1Ext);
273   aBox->GetLastFunction()->SetDescription("");
274   // Apply transformation to box
275   BRepBuilderAPI_Transform aTransformationBox(aBox->GetValue(), aTrsf, Standard_False);
276   TopoDS_Shape aBoxShapeTrsf = aTransformationBox.Shape();
277   aBox->GetLastFunction()->SetValue(aBoxShapeTrsf);
278
279   // Get the shell of the box
280   Handle(GEOM_Object) aShell = Handle(GEOM_Object)::DownCast
281     (myShapesOperations->MakeExplode(aBox, TopAbs_SHELL, true)->Value(1));
282   aBox->GetLastFunction()->SetDescription("");
283   aShell->GetLastFunction()->SetDescription("");
284   // Get the common shapes between shell and shape
285   Handle(GEOM_Object) aCommonCompound = myBooleanOperations->MakeBoolean (theShape, aShell, 1); // MakeCommon
286   if (aCommonCompound.IsNull()) {
287     SetErrorCode(myBooleanOperations->GetErrorCode());
288     return false;
289   }
290   aCommonCompound->GetLastFunction()->SetDescription("");
291   // Explode the faces of common shapes => 3 faces
292   Handle(TColStd_HSequenceOfTransient) aCommonFaces =
293     myShapesOperations->MakeExplode(aCommonCompound, TopAbs_FACE, true);
294   aCommonCompound->GetLastFunction()->SetDescription("");
295   std::list<Handle(GEOM_Object)> aCompoundOfFacesList;
296
297   for (int i=0 ; i<= aCommonFaces->Length()-4 ; i+=4) {
298     std::list<Handle(GEOM_Object)> aFacesList;
299     for (int j = 1 ; j <= 4 ; j++) {
300       Handle(GEOM_Object) aFace = Handle(GEOM_Object)::DownCast(aCommonFaces->Value(i+j)); // Junction faces
301       if (!aFace.IsNull()) {
302         aFace->GetLastFunction()->SetDescription("");
303         aFacesList.push_back(aFace);
304       }
305     }
306     Handle(GEOM_Object) aCompoundOfFaces = myShapesOperations->MakeCompound(aFacesList);
307     if (!aCompoundOfFaces.IsNull()) {
308       aCompoundOfFaces->GetLastFunction()->SetDescription("");
309       aCompoundOfFacesList.push_back(aCompoundOfFaces);
310     }
311   }
312
313   if (aCompoundOfFacesList.size() == 3) {
314     Handle(GEOM_Object) aPln1 = aCompoundOfFacesList.front();
315     aCompoundOfFacesList.pop_front();
316     Handle(GEOM_Object) aPln2 = aCompoundOfFacesList.front();
317     aCompoundOfFacesList.pop_front();
318     Handle(GEOM_Object) aPln3 = aCompoundOfFacesList.front();
319     aCompoundOfFacesList.pop_front();
320     // == END
321     //
322
323
324     //     Uncomment the following lines when GetInPlace bug is solved
325     //     == BEGIN
326 //     Handle(GEOM_Object) aP1 = myBasicOperations->MakePointXYZ(-theL1, 0, 0);
327 //     Handle(GEOM_Object) aP2 = myBasicOperations->MakePointXYZ(-0, 0, theL2);
328 //     Handle(GEOM_Object) aP3 = myBasicOperations->MakePointXYZ(theL1, 0, 0);
329 //     aP1->GetLastFunction()->SetDescription("");
330 //     aP2->GetLastFunction()->SetDescription("");
331 //     aP3->GetLastFunction()->SetDescription("");
332 //     Handle(GEOM_Object) aV1 = myBasicOperations->MakeVectorDXDYDZ(-1, 0, 0);
333 //     Handle(GEOM_Object) aV2 = myBasicOperations->MakeVectorDXDYDZ(0, 0, 1);
334 //     Handle(GEOM_Object) aV3 = myBasicOperations->MakeVectorDXDYDZ(1, 0, 0);
335 //     aV1->GetLastFunction()->SetDescription("");
336 //     aV2->GetLastFunction()->SetDescription("");
337 //     aV3->GetLastFunction()->SetDescription("");
338 //     Handle(GEOM_Object) aPln1 = myBasicOperations->MakePlanePntVec(aP1, aV1, 2*(aR1Ext+theL2));
339 //     Handle(GEOM_Object) aPln2 = myBasicOperations->MakePlanePntVec(aP2, aV2, 2*(aR2Ext));
340 //     Handle(GEOM_Object) aPln3 = myBasicOperations->MakePlanePntVec(aP3, aV3, 2*(aR1Ext+theL2));
341 //     aPln1->GetLastFunction()->SetDescription("");
342 //     aPln2->GetLastFunction()->SetDescription("");
343 //     aPln3->GetLastFunction()->SetDescription("");
344 //
345 //     BRepBuilderAPI_Transform aTransformation1(aPln1->GetValue(), aTrsf, Standard_False);
346 //     TopoDS_Shape aTrsf_Shape1 = aTransformation1.Shape();
347 //     aPln1->GetLastFunction()->SetValue(aTrsf_Shape1);
348 //     BRepBuilderAPI_Transform aTransformation2(aPln2->GetValue(), aTrsf, Standard_False);
349 //     TopoDS_Shape aTrsf_Shape2 = aTransformation2.Shape();
350 //     aPln2->GetLastFunction()->SetValue(aTrsf_Shape2);
351 //     BRepBuilderAPI_Transform aTransformation3(aPln3->GetValue(), aTrsf, Standard_False);
352 //     TopoDS_Shape aTrsf_Shape3 = aTransformation3.Shape();
353 //     aPln3->GetLastFunction()->SetValue(aTrsf_Shape3);
354     //     == END
355     //
356
357     Handle(GEOM_Object) junctionFaces1 = myShapesOperations->GetInPlace(theShape, aPln1);
358     if (junctionFaces1.IsNull())
359       junctionFaces1 = myShapesOperations->GetShapesOnShapeAsCompound
360         (aPln1, theShape, TopAbs_FACE,  GEOMAlgo_ST_ONIN);
361     if (!junctionFaces1.IsNull()) {
362       junctionFaces1->GetLastFunction()->SetDescription("");
363       junctionFaces1->SetName("JUNCTION_FACE_1");
364       theSeq->Append(junctionFaces1);
365     }
366     else {
367       SetErrorCode("Junction face 1 not found");
368       //        theSeq->Append(aPln1);
369       //        return false;
370     }
371     Handle(GEOM_Object) junctionFaces2 = myShapesOperations->GetInPlace(theShape, aPln2);
372     if (junctionFaces2.IsNull())
373       junctionFaces2 = myShapesOperations->GetShapesOnShapeAsCompound
374         (aPln2, theShape, TopAbs_FACE,  GEOMAlgo_ST_ONIN);
375     if (!junctionFaces2.IsNull()) {
376       junctionFaces2->GetLastFunction()->SetDescription("");
377       junctionFaces2->SetName("JUNCTION_FACE_2");
378       theSeq->Append(junctionFaces2);
379     }
380     else {
381       SetErrorCode("Junction face 2 not found");
382       //        theSeq->Append(aPln2);
383       //        return false;
384     }
385     Handle(GEOM_Object) junctionFaces3 = myShapesOperations->GetInPlace(theShape, aPln3);
386     if (junctionFaces3.IsNull())
387       junctionFaces3 = myShapesOperations->GetShapesOnShapeAsCompound
388         (aPln3, theShape, TopAbs_FACE,  GEOMAlgo_ST_ONIN);
389     if (!junctionFaces3.IsNull()) {
390       junctionFaces3->GetLastFunction()->SetDescription("");
391       junctionFaces3->SetName("JUNCTION_FACE_3");
392       theSeq->Append(junctionFaces3);
393     }
394     else {
395       SetErrorCode("Junction face 3 not found");
396       //        theSeq->Append(aPln3);
397       //        return false;
398     }
399   // Comment the following lines when GetInPlace bug is solved
400   // == BEGIN
401   }
402   //     == END
403   /////////////////////////
404   //// Groups of Edges ////
405   /////////////////////////
406   // Result of propagate
407
408   Handle(GEOM_Function) aFunction = theShape->GetLastFunction();
409
410   TCollection_AsciiString theDesc = aFunction->GetDescription();
411   Handle(TColStd_HSequenceOfTransient) aSeqPropagate = myBlocksOperations->Propagate(theShape);
412   if (aSeqPropagate.IsNull() || aSeqPropagate->Length() == 0) {
413     SetErrorCode("Propagation groups not found");
414     return false;
415   }
416   Standard_Integer nbEdges, aNbGroups = aSeqPropagate->Length();
417   // Recover previous description to get rid of Propagate dump
418   aFunction->SetDescription(theDesc);
419
420   bool addGroup;
421   bool circularFoundAndAdded = false;
422   bool incidentPipeFound = false;
423   bool mainPipeFound = false;
424   bool mainPipeFoundAndAdded = false;
425   bool radialFound =false;
426   bool flangeFound = false;
427   bool flangeFoundAndAdded = false;
428   bool chamferOrFilletFound = false;
429
430   for (int i=1 ; i<= aNbGroups; i++) {
431     addGroup = false;
432
433     Handle(GEOM_Object) aGroup = Handle(GEOM_Object)::DownCast(aSeqPropagate->Value(i));
434     if(aGroup.IsNull())
435       continue;
436
437     TopoDS_Shape aGroupShape = aGroup->GetValue();
438     BRepBuilderAPI_Transform aTransformationShapeInv(aGroupShape, aTrsfInv, Standard_False);
439     TopoDS_Shape aGroupShapeTrsfInv = aTransformationShapeInv.Shape();
440
441     TopTools_IndexedMapOfShape anEdgesMap;
442     TopExp::MapShapes(aGroupShapeTrsfInv,TopAbs_EDGE, anEdgesMap);
443     nbEdges = anEdgesMap.Extent();
444
445     if (shapeType == TSHAPE_BASIC) {
446       if ((nbEdges == 21) || /*R1Ext = R2Ext*/(nbEdges == 17)){
447         addGroup = true;
448         aGroup->SetName("THICKNESS");
449       }
450       else if (nbEdges == 6) {
451         if (!circularFoundAndAdded) {
452           circularFoundAndAdded = true;
453           addGroup = true;
454           aGroup->SetName("CIRCULAR_QUARTER_PIPE");
455         }
456       }
457       else if (nbEdges == 8) {
458         incidentPipeFound = true;
459         mainPipeFound = false;
460         radialFound =false;
461         flangeFound = false;
462
463         TopExp_Explorer Ex(aGroupShapeTrsfInv,TopAbs_VERTEX);
464         while (Ex.More()) {
465           gp_Pnt aP =  BRep_Tool::Pnt(TopoDS::Vertex(Ex.Current()));
466           double x=aP.X(), y=aP.Y(), z=aP.Z();
467
468
469           if ((Abs(x) > aR2Ext + Precision::Confusion()) ||
470               (Abs(y) > aR2Ext + Precision::Confusion())) {
471             incidentPipeFound = false;
472           }
473
474           if ( z < -Precision::Confusion()) {
475             // length of main pipe
476             mainPipeFound = true;
477             if (!mainPipeFoundAndAdded) {
478               mainPipeFoundAndAdded = true;
479               addGroup = true;
480               aGroup->SetName("HALF_LENGTH_MAIN_PIPE");
481             }
482           }
483
484           else if (Abs(x) > (theL1-Precision::Confusion())) {
485             // discretisation circulaire
486             radialFound = true;
487             if (!circularFoundAndAdded) {
488               circularFoundAndAdded = true;
489               addGroup = true;
490               aGroup->SetName("CIRCULAR_QUARTER_PIPE");
491             }
492           }
493           Ex.Next();
494         }
495         if (incidentPipeFound) {
496           addGroup = true;
497           aGroup->SetName("HALF_LENGTH_INCIDENT_PIPE");
498         }
499         if (!addGroup && (!incidentPipeFound &&
500                           !radialFound &&
501                           !mainPipeFound &&
502                           !flangeFound)) {
503           // Flange (collerette)
504           flangeFound = true;
505           addGroup = true;
506           aGroup->SetName("FLANGE");
507         }
508       }
509       else
510         continue;
511     }
512     else if (shapeType == TSHAPE_CHAMFER || shapeType == TSHAPE_FILLET) {
513       if (nbEdges == 25) {
514         addGroup = true;
515         aGroup->SetName("THICKNESS");
516       }
517       else if ((nbEdges == 10) || (nbEdges == 6)) {
518         if (!circularFoundAndAdded) {
519           addGroup = true;
520           circularFoundAndAdded = true;
521           aGroup->SetName("CIRCULAR_QUARTER_PIPE");
522         }
523       }
524       else if (nbEdges == 8) {
525         incidentPipeFound = true;
526         mainPipeFound = true;
527         flangeFound = false;
528
529         TopExp_Explorer Ex(aGroupShapeTrsfInv,TopAbs_VERTEX);
530         while (Ex.More()) {
531           gp_Pnt aP =  BRep_Tool::Pnt(TopoDS::Vertex(Ex.Current()));
532           double x=aP.X(), y=aP.Y(), z=aP.Z();
533
534           // tuy_princ_long_avant & tuy_princ_long_apres
535           bool isMain = (((z < Precision::Confusion()) || (x < Precision::Confusion())) &&
536                          ((y <= aR1Ext + Precision::Confusion()) ||
537                           (y <= -(aR1Ext + Precision::Confusion())) ||
538                           (y <= theR1 + Precision::Confusion()) ||
539                           (y == -(theR1 + Precision::Confusion()))));
540
541           if (!isMain) {
542             mainPipeFound = false;
543           }
544
545           // collerette
546           if (z < Precision::Confusion()) {
547             flangeFound = true;
548             if (!flangeFoundAndAdded) {
549               flangeFoundAndAdded = true;
550               addGroup = true;
551               aGroup->SetName("FLANGE");
552             }
553           }
554
555           // tuyau incident
556           if ((Abs(x) > aR2Ext + Precision::Confusion()) ||
557               (Abs(y) > aR2Ext + Precision::Confusion())) {
558             incidentPipeFound = false;
559           }
560           Ex.Next();
561         }
562         if (mainPipeFound) {
563           addGroup = true;
564           aGroup->SetName("HALF_LENGTH_MAIN_PIPE");
565         }
566         if (incidentPipeFound) {
567           addGroup = true;
568           aGroup->SetName("HALF_LENGTH_INCIDENT_PIPE");
569         }
570         if (!addGroup && (!incidentPipeFound &&
571                           !mainPipeFound &&
572                           !flangeFound &&
573                           !chamferOrFilletFound)) {
574           addGroup = true;
575           chamferOrFilletFound = true;
576           if (shapeType == TSHAPE_CHAMFER)
577             aGroup->SetName("CHAMFER");
578           else
579             aGroup->SetName("FILLET");
580         }
581       }
582       else
583         continue;
584     }
585     // Add group to the list
586     if (addGroup)
587       theSeq->Append(aGroup);
588   }
589
590   SetErrorCode(OK);
591   return true;
592 }
593
594 bool GEOMImpl_IAdvancedOperations::MakePipeTShapePartition(Handle(GEOM_Object) theShape,
595                                                            double theR1, double theW1, double theL1,
596                                                            double theR2, double theW2, double theL2,
597                                                            double theH, double theW,
598                                                            double theRF, bool isNormal)
599 {
600   SetErrorCode(KO);
601
602   // Build tools for partition operation:
603   // 1 face and 2 planes
604   // Face
605   Handle(GEOM_Object) arete_intersect_int;
606   Handle(GEOM_Object) wire_t, wire_t2, face_t, face_t2;
607   Handle(GEOM_Object) chan_racc;
608   Handle(GEOM_Object) vi1, vi2;
609
610   Handle(GEOM_Object) Vector_Z = myBasicOperations->MakeVectorDXDYDZ(0, 0, 1);
611   Vector_Z->GetLastFunction()->SetDescription("");
612
613   // Useful values
614   double aSize = 2*(theL1 + theL2);
615   double aR1Ext = theR1 + theW1;
616   double aR2Ext = theR2 + theW2;
617   double theVertCylinderRadius = aR2Ext + theW + theRF;
618   double theHoriCylinderRadius = aR1Ext + theH + theRF;
619
620   // Common edges on internal cylinder
621   Handle(GEOM_Object) box_i = my3DPrimOperations->MakeBoxDXDYDZ(theR2, theR2, theR1);
622   box_i->GetLastFunction()->SetDescription("");
623   box_i = myTransformOperations->TranslateDXDYDZ(box_i, -theR2, -theR2, 0);
624   box_i->GetLastFunction()->SetDescription("");
625
626   Handle(GEOM_Function) aFunction = theShape->GetLastFunction();
627   TCollection_AsciiString theDesc = aFunction->GetDescription();
628   Handle(TColStd_HSequenceOfTransient) edges_i =
629     myShapesOperations->GetShapesOnBox(box_i, theShape, TopAbs_EDGE, GEOMAlgo_ST_IN);
630   // Recover previous description to get rid of Propagate dump
631   aFunction->SetDescription(theDesc);
632   if (edges_i.IsNull() || edges_i->Length() == 0) {
633     SetErrorCode("Internal edges not found");
634     return false;
635   }
636   for (int i=1; i<=edges_i->Length();i++) {
637     Handle(GEOM_Object) anObj = Handle(GEOM_Object)::DownCast(edges_i->Value(i));
638     anObj->GetLastFunction()->SetDescription("");
639   }
640   arete_intersect_int = Handle(GEOM_Object)::DownCast(edges_i->Value(1));
641
642   // search for vertices located on both internal pipes
643   aFunction = theShape->GetLastFunction();
644   theDesc = aFunction->GetDescription();
645   Handle(TColStd_HSequenceOfTransient) vertices_i =
646     myShapesOperations->GetShapesOnBox(box_i, theShape, TopAbs_VERTEX, GEOMAlgo_ST_ONIN);
647   // Recover previous description to get rid of Propagate dump
648   aFunction->SetDescription(theDesc);
649   if (vertices_i.IsNull() || vertices_i->Length() == 0) {
650     SetErrorCode("Internal vertices not found");
651     return false;
652   }
653
654   for (int i = 1; i <= vertices_i->Length(); i++) {
655     Handle(GEOM_Object) v = Handle(GEOM_Object)::DownCast(vertices_i->Value(i));
656     v->GetLastFunction()->SetDescription("");
657     TopoDS_Vertex aVertex = TopoDS::Vertex(v->GetValue());
658     gp_Pnt aP = BRep_Tool::Pnt(aVertex);
659     if (Abs(aP.X()) <= Precision::Confusion()) {
660       if (Abs(aP.Y()) - theR2 <= Precision::Confusion())
661         vi1 = v;
662     } else if (Abs(aP.Y()) <= Precision::Confusion()) {
663       if (Abs(aP.X()) - theR1 <= Precision::Confusion())
664         vi2 = v;
665     }
666   }
667
668   std::list<Handle(GEOM_Object)> theShapes;
669
670   if (isNormal) {
671     Handle(GEOM_Object) ve1, ve2;
672
673     Handle(GEOM_Object) box_e = my3DPrimOperations->MakeBoxDXDYDZ(aR2Ext, aR2Ext, aR1Ext);
674     box_e->GetLastFunction()->SetDescription("");
675     box_e = myTransformOperations->TranslateDXDYDZ(box_e, -aR2Ext, -aR2Ext, 0);
676     box_e->GetLastFunction()->SetDescription("");
677     // Common edges on external cylinder
678     aFunction = theShape->GetLastFunction();
679     theDesc = aFunction->GetDescription();
680     Handle(TColStd_HSequenceOfTransient) edges_e =
681       myShapesOperations->GetShapesOnBox(box_e, theShape, TopAbs_EDGE, GEOMAlgo_ST_IN);
682     // Recover previous description to get rid of Propagate dump
683     aFunction->SetDescription(theDesc);
684     if (edges_e.IsNull() || edges_e->Length() == 0) {
685       SetErrorCode("External edges not found");
686       return false;
687     }
688     for (int i=1; i<=edges_e->Length();i++) {
689       Handle(GEOM_Object) anObj = Handle(GEOM_Object)::DownCast(edges_e->Value(i));
690       anObj->GetLastFunction()->SetDescription("");
691     }
692
693     // search for vertices located on both external pipes
694     aFunction = theShape->GetLastFunction();
695     theDesc = aFunction->GetDescription();
696     Handle(TColStd_HSequenceOfTransient) vertices_e =
697       myShapesOperations->GetShapesOnBox(box_e, theShape, TopAbs_VERTEX, GEOMAlgo_ST_ONIN);
698     // Recover previous description to get rid of Propagate dump
699     aFunction->SetDescription(theDesc);
700     if (vertices_e.IsNull() || vertices_e->Length() == 0) {
701       SetErrorCode("External vertices not found");
702       return false;
703     }
704
705     for (int i = 1; i <= vertices_e->Length(); i++) {
706       Handle(GEOM_Object) v = Handle(GEOM_Object)::DownCast(vertices_e->Value(i));
707       v->GetLastFunction()->SetDescription("");
708       TopoDS_Vertex aVertex = TopoDS::Vertex(v->GetValue());
709       gp_Pnt aP = BRep_Tool::Pnt(aVertex);
710       if (Abs(aP.X()) <= Precision::Confusion()) {
711         if (Abs(aP.Y()) - theR2 > Precision::Confusion())
712           ve1 = v;
713       } else if (Abs(aP.Y()) <= Precision::Confusion()) {
714         if (Abs(aP.X()) - theR2 > Precision::Confusion())
715           ve2 = v;
716       }
717     }
718     Handle(GEOM_Object) edge_e1, edge_e2;
719     try {
720 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
721       OCC_CATCH_SIGNALS;
722 #endif
723       edge_e1 = myBasicOperations->MakeLineTwoPnt(ve1, vi1);
724       if (edge_e1.IsNull()) {
725         SetErrorCode("Edge 1 could not be built");
726         return false;
727       }
728     } catch (Standard_Failure) {
729       Handle(Standard_Failure) aFail = Standard_Failure::Caught();
730       SetErrorCode(aFail->GetMessageString());
731       return false;
732     }
733
734     try {
735 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
736       OCC_CATCH_SIGNALS;
737 #endif
738       edge_e2 = myBasicOperations->MakeLineTwoPnt(ve2, vi2);
739       if (edge_e2.IsNull()) {
740         SetErrorCode("Edge 2 could not be built");
741         return false;
742       }
743     } catch (Standard_Failure) {
744       Handle(Standard_Failure) aFail = Standard_Failure::Caught();
745       SetErrorCode(aFail->GetMessageString());
746       return false;
747     }
748
749     edge_e1->GetLastFunction()->SetDescription("");
750     edge_e2->GetLastFunction()->SetDescription("");
751
752     std::list<Handle(GEOM_Object)> edge_e_elist;
753     edge_e_elist.push_back(arete_intersect_int);
754     edge_e_elist.push_back(edge_e1);
755     edge_e_elist.push_back(Handle(GEOM_Object)::DownCast(edges_e->Value(1)));
756     edge_e_elist.push_back(edge_e2);
757     wire_t = myShapesOperations->MakeWire(edge_e_elist, 1e-7);
758     if (wire_t.IsNull()) {
759       SetErrorCode("Impossible to build wire");
760       return false;
761     }
762     wire_t->GetLastFunction()->SetDescription("");
763     face_t = myShapesOperations->MakeFace(wire_t, false);
764     if (face_t.IsNull()) {
765       SetErrorCode("Impossible to build face");
766       return false;
767     }
768     face_t->GetLastFunction()->SetDescription("");
769   }
770   else {
771     Handle(GEOM_Object) P1, P2, P3, P4, P5, P6;
772     int idP1, idP2, idP3, idP4;
773     int PZX, PZY;
774     double ZX=0, ZY=0;
775     std::vector<int> LX;
776     std::vector<int> LY;
777     Handle(GEOM_Object) box_e = my3DPrimOperations->MakeBoxDXDYDZ
778       (theVertCylinderRadius, theVertCylinderRadius, theHoriCylinderRadius);
779     box_e->GetLastFunction()->SetDescription("");
780     box_e = myTransformOperations->TranslateDXDYDZ
781       (box_e, -theVertCylinderRadius, -theVertCylinderRadius, 0);
782     box_e->GetLastFunction()->SetDescription("");
783
784     aFunction = theShape->GetLastFunction();
785     theDesc = aFunction->GetDescription();
786     Handle(TColStd_HSequenceOfTransient) extremVertices =
787       myShapesOperations->GetShapesOnBox(box_e, theShape, TopAbs_VERTEX, GEOMAlgo_ST_ONIN);
788     // Recover previous description to get rid of Propagate dump
789     aFunction->SetDescription(theDesc);
790
791     if (extremVertices.IsNull() || extremVertices->Length() == 0) {
792       if (theRF == 0)
793         SetErrorCode("Vertices on chamfer not found");
794       else
795         SetErrorCode("Vertices on fillet not found");
796       return false;
797     }
798
799     theShapes.push_back(theShape);
800     theShapes.push_back(box_e);
801     if (extremVertices->Length() != 6) {
802       //           for (int i=1; i<=extremVertices->Length(); i++){
803       //             theShapes.push_back(Handle(GEOM_Object)::DownCast(extremVertices->Value(i)));
804       //           }
805       //           Handle(GEOM_Object) aCompound = myShapesOperations->MakeCompound(theShapes);
806       //           TopoDS_Shape aCompoundShape = aCompound->GetValue();
807       //           theShape->GetLastFunction()->SetValue(aCompoundShape);
808       SetErrorCode("Bad number of vertices on chamfer found");
809       return false;
810     }
811
812     for (int i=1; i<=extremVertices->Length(); i++){
813       Handle(GEOM_Object) aV = Handle(GEOM_Object)::DownCast(extremVertices->Value(i));
814       aV->GetLastFunction()->SetDescription("");
815       gp_Pnt aP = BRep_Tool::Pnt(TopoDS::Vertex(aV->GetValue()));
816
817       if (Abs(aP.X()) <= Precision::Confusion()) {
818         if (Abs(aP.Y()) - theR2 > Precision::Confusion()) {
819           LX.push_back(i);
820           if  (aP.Z()-ZX > Precision::Confusion()) {
821             ZX = aP.Z();
822             PZX = i;
823           }
824         }
825       }
826       else {
827         if (Abs(aP.X()) - theR2 > Precision::Confusion()) {
828           LY.push_back(i);
829           if (aP.Z() - ZY > Precision::Confusion()) {
830             ZY = aP.Z();
831             PZY = i;
832           }
833         }
834       }
835     }
836
837     idP2 = PZX;
838     idP4 = PZY;
839     idP1 = LX.at(0);
840     if (LX.at(0) == PZX)
841       idP1 = LX.at(1);
842     idP3 = LY.at(0);
843     if (LY.at(0) == PZY)
844       idP3 = LY.at(1);
845
846     P1 = Handle(GEOM_Object)::DownCast(extremVertices->Value(idP1));
847     P2 = Handle(GEOM_Object)::DownCast(extremVertices->Value(idP2));
848     P3 = Handle(GEOM_Object)::DownCast(extremVertices->Value(idP3));
849     P4 = Handle(GEOM_Object)::DownCast(extremVertices->Value(idP4));
850
851     Handle(GEOM_Object) Cote_1 = myBasicOperations->MakeLineTwoPnt(P1, vi1);
852     if (Cote_1.IsNull()) {
853       SetErrorCode("Impossible to build edge in thickness");
854       return false;
855     }
856     Cote_1->GetLastFunction()->SetDescription("");
857
858     Handle(GEOM_Object) Cote_2 = myBasicOperations->MakeLineTwoPnt(vi2, P3);
859     if (Cote_2.IsNull()) {
860       SetErrorCode("Impossible to build edge in thickness");
861       return false;
862     }
863     Cote_2->GetLastFunction()->SetDescription("");
864
865     // edge_chan_princ = arete du chanfrein (ou raccord) sur le tuyau principal
866     // edge_chan_inc = arete du chanfrein (ou raccord) sur le tuyau incident
867     //         std::cerr << "Getting chamfer edge on main pipe" << std::endl;
868     Handle(GEOM_Object) edge_chan_princ = myBlocksOperations->GetEdge(theShape, P1, P3);
869     if (edge_chan_princ.IsNull()) {
870       SetErrorCode("Impossible to find edge on main pipe");
871       return false;
872     }
873     edge_chan_princ->GetLastFunction()->SetDescription("");
874
875     Handle(GEOM_Object) edge_chan_inc = myBlocksOperations->GetEdge(theShape, P2, P4);
876     if (edge_chan_inc.IsNull()) {
877       SetErrorCode("Impossible to find edge on incident pipe");
878       return false;
879     }
880     edge_chan_inc->GetLastFunction()->SetDescription("");
881
882     std::list<Handle(GEOM_Object)> edgeList1;
883     edgeList1.push_back(edge_chan_princ);
884     edgeList1.push_back(Cote_1);
885     edgeList1.push_back(arete_intersect_int);
886     edgeList1.push_back(Cote_2);
887
888     //         std::cerr << "Creating wire 1" << std::endl;
889     wire_t = myShapesOperations->MakeWire(edgeList1, 1e-7);
890     if (wire_t.IsNull()) {
891       SetErrorCode("Impossible to build wire");
892       return false;
893     }
894     wire_t->GetLastFunction()->SetDescription("");
895
896     //         std::cerr << "Creating face 1" << std::endl;
897     face_t = myShapesOperations->MakeFace(wire_t, false);
898     if (face_t.IsNull()) {
899       SetErrorCode("Impossible to build face");
900       return false;
901     }
902     face_t->GetLastFunction()->SetDescription("");
903     theShapes.push_back(face_t);
904
905     gp_Pnt aP2 = BRep_Tool::Pnt(TopoDS::Vertex(P2->GetValue()));
906     gp_Pnt aP5 = BRep_Tool::Pnt(TopoDS::Vertex(vi1->GetValue()));
907     double deltaZ = aP2.Z() - aP5.Z();
908     //         std::cerr << "Creating new point from vi1 with deltaZ = " << deltaZ << std::endl;
909     Handle(GEOM_Object) P5bis = myTransformOperations->TranslateDXDYDZCopy(vi1, 0, 0, deltaZ);
910     if (P5bis.IsNull()) {
911       SetErrorCode("Impossible to translate vertex");
912       return false;
913     }
914     P5bis->GetLastFunction()->SetDescription("");
915
916     gp_Pnt aP4 = BRep_Tool::Pnt(TopoDS::Vertex(P4->GetValue()));
917     gp_Pnt aP6 = BRep_Tool::Pnt(TopoDS::Vertex(vi2->GetValue()));
918     deltaZ = aP4.Z() - aP6.Z();
919     //         std::cerr << "Creating new point from vi2 with deltaZ = " << deltaZ << std::endl;
920     Handle(GEOM_Object) P6bis = myTransformOperations->TranslateDXDYDZCopy(vi2, 0, 0, deltaZ);
921     if (P6bis.IsNull()) {
922       SetErrorCode("Impossible to translate vertex");
923       return false;
924     }
925     P6bis->GetLastFunction()->SetDescription("");
926
927     //         std::cerr << "Creating new line 1 from 2 previous points" << std::endl;
928     Handle(GEOM_Object) Cote_3 = myBasicOperations->MakeLineTwoPnt(P5bis, P2);
929     if (Cote_3.IsNull()) {
930       SetErrorCode("Impossible to build edge in thickness");
931       return false;
932     }
933     Cote_3->GetLastFunction()->SetDescription("");
934
935     //         std::cerr << "Creating new line 2 from 2 previous points" << std::endl;
936     Handle(GEOM_Object) Cote_4 = myBasicOperations->MakeLineTwoPnt(P6bis, P4);
937     if (Cote_4.IsNull()) {
938       SetErrorCode("Impossible to build edge in thickness");
939       return false;
940     }
941     Cote_4->GetLastFunction()->SetDescription("");
942
943     //         std::cerr << "Creating new line 3 from 2 previous points" << std::endl;
944     Handle(GEOM_Object) Cote_5 = myBasicOperations->MakeLineTwoPnt(P5bis, P6bis);
945     if (Cote_4.IsNull()) {
946       SetErrorCode("Impossible to build edge in thickness");
947       return false;
948     }
949     Cote_5->GetLastFunction()->SetDescription("");
950
951     //std::list<Handle(GEOM_Object)> edgeList2;
952     //edgeList2.push_back(edge_chan_inc);
953     //edgeList2.push_back(Cote_3);
954     //edgeList2.push_back(Cote_5);
955     //edgeList2.push_back(Cote_4);
956     //         std::cerr << "Creating wire 2" << std::endl;
957     //wire_t2 = myShapesOperations->MakeWire(edgeList2, 1e-7);
958     //if (wire_t2.IsNull()) {
959     //  SetErrorCode("Impossible to build wire");
960     //  return false;
961     //}
962     //wire_t2->GetLastFunction()->SetDescription("");
963     //         std::cerr << "Creating face 2" << std::endl;
964     //face_t2 = myShapesOperations->MakeFace(wire_t2, false);
965     face_t2 = my3DPrimOperations->MakePrismVecH(edge_chan_inc, Cote_4, - 2.0*theR2);
966     if (face_t2.IsNull()) {
967       SetErrorCode("Impossible to build face");
968       return false;
969     }
970     face_t2->GetLastFunction()->SetDescription("");
971     theShapes.push_back(face_t2);
972   }
973
974   // Planes
975   Handle(GEOM_Object) aP0 = myBasicOperations->MakePointXYZ(0, 0, 0);
976   Handle(GEOM_Object) aVZ = myBasicOperations->MakeVectorDXDYDZ(0, 0, 1);
977   Handle(GEOM_Object) aVXZ = myBasicOperations->MakeVectorDXDYDZ(aR1Ext, 0, 0.5*(theL1+theVertCylinderRadius));
978   Handle(GEOM_Object) aPlnOZ = myBasicOperations->MakePlanePntVec(aP0, aVZ, aSize);
979   Handle(GEOM_Object) aPlnOXZ = myBasicOperations->MakePlanePntVec(aP0, aVXZ, aSize);
980   aP0->GetLastFunction()->SetDescription("");
981   aVZ->GetLastFunction()->SetDescription("");
982   aVXZ->GetLastFunction()->SetDescription("");
983   aPlnOZ->GetLastFunction()->SetDescription("");
984   aPlnOXZ->GetLastFunction()->SetDescription("");
985   theShapes.push_back(aPlnOZ);
986   theShapes.push_back(aPlnOXZ);
987
988   // Partition
989   Handle(TColStd_HSequenceOfTransient) partitionShapes = new TColStd_HSequenceOfTransient;
990   Handle(TColStd_HSequenceOfTransient) theTools = new TColStd_HSequenceOfTransient;
991   Handle(TColStd_HSequenceOfTransient) theKeepInside = new TColStd_HSequenceOfTransient;
992   Handle(TColStd_HSequenceOfTransient) theRemoveInside = new TColStd_HSequenceOfTransient;
993   Handle(TColStd_HArray1OfInteger) theMaterials;
994   partitionShapes->Append(theShape);
995   theTools->Append(aPlnOZ);
996   if (Abs(aR1Ext - aR2Ext) > Precision::Confusion() )
997     theTools->Append(aPlnOXZ);
998   theTools->Append(face_t);
999   if (!isNormal)
1000     theTools->Append(face_t2);
1001
1002   Handle(GEOM_Object) Te3 = myBooleanOperations->MakePartition
1003     (partitionShapes, theTools, theKeepInside, theRemoveInside,
1004      TopAbs_SOLID, false, theMaterials, 0, false);
1005   if (Te3.IsNull()) {
1006     SetErrorCode("Impossible to build partition of TShape");
1007     //         Handle(GEOM_Object) aCompound = myShapesOperations->MakeCompound(theShapes);
1008     //         TopoDS_Shape aCompoundShape = aCompound->GetValue();
1009     //         theShape->GetLastFunction()->SetValue(aCompoundShape);
1010     return false;
1011   }
1012   Te3->GetLastFunction()->SetDescription("");
1013
1014   // Last verification: result should be a block
1015   std::list<GEOMImpl_IBlocksOperations::BCError> errList;
1016   if (!myBlocksOperations->CheckCompoundOfBlocks(Te3,errList)) {
1017     SetErrorCode("TShape is not a block");
1018     return false;
1019   }
1020   TopoDS_Shape aShape = Te3->GetValue();
1021   theShape->GetLastFunction()->SetValue(aShape);
1022
1023   SetErrorCode(OK);
1024   return true;
1025 }
1026
1027 // Mirror and glue faces
1028 bool GEOMImpl_IAdvancedOperations::MakePipeTShapeMirrorAndGlue(Handle(GEOM_Object) theShape,
1029                                                                double theR1, double theW1, double theL1,
1030                                                                double theR2, double theW2, double theL2)
1031 {
1032   SetErrorCode(KO);
1033
1034   // Useful values
1035   double aSize = 2*(theL1 + theL2);
1036   double aR1Ext = theR1 + theW1;
1037
1038   // Planes
1039   Handle(GEOM_Object) aP0 = myBasicOperations->MakePointXYZ(0, 0, 0);
1040   aP0->GetLastFunction()->SetDescription("");
1041   Handle(GEOM_Object) aVX = myBasicOperations->MakeVectorDXDYDZ(1, 0, 0);
1042   Handle(GEOM_Object) aVY = myBasicOperations->MakeVectorDXDYDZ(0, 1, 0);
1043   aVX->GetLastFunction()->SetDescription("");
1044   aVY->GetLastFunction()->SetDescription("");
1045   Handle(GEOM_Object) aPlane_OX = myBasicOperations->MakePlanePntVec(aP0, aVX, 2*(aR1Ext + theL2));
1046   Handle(GEOM_Object) aPlane_OY = myBasicOperations->MakePlanePntVec(aP0, aVY, aSize);
1047   aPlane_OX->GetLastFunction()->SetDescription("");
1048   aPlane_OY->GetLastFunction()->SetDescription("");
1049
1050   Handle(GEOM_Object) Te4 = myTransformOperations->MirrorPlaneCopy(theShape, aPlane_OX);
1051   if (Te4.IsNull()) {
1052     SetErrorCode("Impossible to build mirror of quarter TShape");
1053     return false;
1054   }
1055
1056   Handle(GEOM_Object) Te5 = myTransformOperations->MirrorPlaneCopy(theShape, aPlane_OY);
1057   if (Te5.IsNull()) {
1058     SetErrorCode("Impossible to build mirror of half TShape");
1059     return false;
1060   }
1061
1062   Handle(GEOM_Object) Te6 = myTransformOperations->MirrorPlaneCopy(Te4, aPlane_OY);
1063   if (Te6.IsNull()) {
1064     SetErrorCode("Impossible to build mirror of half TShape");
1065     return false;
1066   }
1067
1068   std::list<Handle(GEOM_Object)> aShapesList;
1069   aShapesList.push_back(theShape);
1070   aShapesList.push_back(Te4);
1071   aShapesList.push_back(Te5);
1072   aShapesList.push_back(Te6);
1073   Handle(GEOM_Object) Te7 = myShapesOperations->MakeCompound(aShapesList);
1074   if (Te7.IsNull()) {
1075     SetErrorCode("Impossible to build compound");
1076     return false;
1077   }
1078
1079   Handle(GEOM_Object) Te8 = myShapesOperations->MakeGlueFaces(Te7, 1e-7, true);
1080   if (Te8.IsNull()) {
1081     SetErrorCode("Impossible to glue faces of TShape");
1082     return false;
1083   }
1084
1085   TopoDS_Shape aShape = Te8->GetValue();
1086
1087   theShape->GetLastFunction()->SetValue(aShape);
1088
1089   Te4->GetLastFunction()->SetDescription("");
1090   Te5->GetLastFunction()->SetDescription("");
1091   Te6->GetLastFunction()->SetDescription("");
1092   Te7->GetLastFunction()->SetDescription("");
1093   Te8->GetLastFunction()->SetDescription("");
1094
1095   SetErrorCode(OK);
1096   return true;
1097 }
1098
1099 //=============================================================================
1100 /*!
1101  *  MakePipeTShape
1102  *  Create a T-shape object with specified caracteristics for the main and
1103  *  the incident pipes (radius, width, half-length).
1104  *  Center of the shape is (0,0,0). The main plane of the T-shape is XOY.
1105  *  \param theR1 Internal radius of main pipe
1106  *  \param theW1 Width of main pipe
1107  *  \param theL1 Half-length of main pipe
1108  *  \param theR2 Internal radius of incident pipe (R2 < R1)
1109  *  \param theW2 Width of incident pipe (R2+W2 < R1+W1)
1110  *  \param theL2 Half-length of incident pipe
1111  *  \param theHexMesh Boolean indicating if shape is prepared for hex mesh
1112  *  \return List of GEOM_Objects, containing the created shape and propagation groups.
1113  */
1114 //=============================================================================
1115 Handle(TColStd_HSequenceOfTransient)
1116 GEOMImpl_IAdvancedOperations::MakePipeTShape(double theR1, double theW1, double theL1,
1117                                              double theR2, double theW2, double theL2,
1118                                              bool theHexMesh)
1119 {
1120   MESSAGE("GEOMImpl_IAdvancedOperations::MakePipeTShape");
1121   SetErrorCode(KO);
1122   //Add a new object
1123   Handle(GEOM_Object) aShape = GetEngine()->AddObject(GetDocID(), GEOM_TSHAPE);
1124
1125   //Add a new shape function with parameters
1126   Handle(GEOM_Function) aFunction = aShape->AddFunction(GEOMImpl_PipeTShapeDriver::GetID(), TSHAPE_BASIC);
1127   if (aFunction.IsNull()) return NULL;
1128
1129   //Check if the function is set correctly
1130   if (aFunction->GetDriverGUID() != GEOMImpl_PipeTShapeDriver::GetID()) return NULL;
1131
1132   GEOMImpl_IPipeTShape aData(aFunction);
1133
1134   aData.SetR1(theR1);
1135   aData.SetW1(theW1);
1136   aData.SetL1(theL1);
1137   aData.SetR2(theR2);
1138   aData.SetW2(theW2);
1139   aData.SetL2(theL2);
1140   aData.SetHexMesh(theHexMesh);
1141
1142   //Compute the resulting value
1143   try {
1144 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
1145     OCC_CATCH_SIGNALS;
1146 #endif
1147     if (!GetSolver()->ComputeFunction(aFunction)) {
1148       SetErrorCode("TShape driver failed");
1149       return NULL;
1150     }
1151   } catch (Standard_Failure) {
1152     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1153     SetErrorCode(aFail->GetMessageString());
1154     return NULL;
1155   }
1156
1157   if (theHexMesh) {
1158     if (!MakePipeTShapePartition(aShape, theR1, theW1, theL1, theR2, theW2, theL2))
1159       return NULL;
1160     if (!MakePipeTShapeMirrorAndGlue(aShape, theR1, theW1, theL1, theR2, theW2, theL2))
1161       return NULL;
1162   }
1163
1164   Handle(TColStd_HSequenceOfTransient) aSeq = new TColStd_HSequenceOfTransient;
1165   aSeq->Append(aShape);
1166
1167   if (theHexMesh) {
1168     /*
1169      * Get the groups: BEGIN
1170      */
1171     try {
1172       if (!MakeGroups(aShape, TSHAPE_BASIC, theR1, theW1, theL1, theR2, theW2, theL2, aSeq, gp_Trsf()))
1173         return NULL;
1174     }
1175     catch (Standard_Failure) {
1176       Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1177       SetErrorCode(aFail->GetMessageString());
1178       return NULL;
1179     }
1180
1181     TCollection_AsciiString aListRes, anEntry;
1182     // Iterate over the sequence aSeq
1183     Standard_Integer aNbGroups = aSeq->Length();
1184     Standard_Integer i = 2;
1185     for (; i <= aNbGroups; i++) {
1186       Handle(Standard_Transient) anItem = aSeq->Value(i);
1187       if (anItem.IsNull()) continue;
1188       Handle(GEOM_Object) aGroup = Handle(GEOM_Object)::DownCast(anItem);
1189       if (aGroup.IsNull()) continue;
1190       //Make a Python command
1191       TDF_Tool::Entry(aGroup->GetEntry(), anEntry);
1192       aListRes += anEntry + ", ";
1193     }
1194
1195     aListRes.Trunc(aListRes.Length() - 2);
1196
1197     //Make a Python command
1198     GEOM::TPythonDump(aFunction)
1199       << "[" << aShape << ", " << aListRes.ToCString() << "] = geompy.MakePipeTShape("
1200       << theR1 << ", " << theW1 << ", " << theL1 << ", " << theR2 << ", " << theW2 << ", " << theL2 << ", "
1201       << theHexMesh << ")";
1202   }
1203   /*
1204    * Get the groups: END
1205    */
1206   else {
1207     //Make a Python command
1208     GEOM::TPythonDump(aFunction)
1209       << "[" << aShape << "] = geompy.MakePipeTShape(" << theR1 << ", " << theW1 << ", "
1210       << theL1 << ", " << theR2 << ", " << theW2 << ", " << theL2 << ", " << theHexMesh << ")";
1211   }
1212
1213   SetErrorCode(OK);
1214
1215   return aSeq;
1216 }
1217
1218 //=============================================================================
1219 /*!
1220  *  MakePipeTShapeWithPosition
1221  *  Create a T-shape object with specified caracteristics for the main and
1222  *  the incident pipes (radius, width, half-length).
1223  *  The extremities of the main pipe are located on junctions points P1 and P2.
1224  *  The extremity of the incident pipe is located on junction point P3.
1225  *  \param theR1 Internal radius of main pipe
1226  *  \param theW1 Width of main pipe
1227  *  \param theL1 Half-length of main pipe
1228  *  \param theR2 Internal radius of incident pipe (R2 < R1)
1229  *  \param theW2 Width of incident pipe (R2+W2 < R1+W1)
1230  *  \param theL2 Half-length of incident pipe
1231  *  \param theHexMesh Boolean indicating if shape is prepared for hex mesh
1232  *  \param theP1 1st junction point of main pipe
1233  *  \param theP2 2nd junction point of main pipe
1234  *  \param theP3 Junction point of incident pipe
1235  *  \return List of GEOM_Objects, containing the created shape and propagation groups..
1236  */
1237 //=============================================================================
1238 Handle(TColStd_HSequenceOfTransient)
1239 GEOMImpl_IAdvancedOperations::MakePipeTShapeWithPosition(double theR1, double theW1, double theL1,
1240                                                          double theR2, double theW2, double theL2,
1241                                                          bool theHexMesh,
1242                                                          Handle(GEOM_Object) theP1,
1243                                                          Handle(GEOM_Object) theP2,
1244                                                          Handle(GEOM_Object) theP3)
1245 {
1246   SetErrorCode(KO);
1247   //Add a new object
1248   Handle(GEOM_Object) aShape = GetEngine()->AddObject(GetDocID(), GEOM_TSHAPE);
1249   /////////////////
1250   // TSHAPE CODE
1251   /////////////////
1252   //Add a new shape function with parameters
1253   Handle(GEOM_Function) aFunction = aShape->AddFunction(GEOMImpl_PipeTShapeDriver::GetID(), TSHAPE_BASIC);
1254   if (aFunction.IsNull()) return NULL;
1255
1256   //Check if the function is set correctly
1257   if (aFunction->GetDriverGUID() != GEOMImpl_PipeTShapeDriver::GetID()) return NULL;
1258
1259   // Check new position
1260   if (!CheckCompatiblePosition(theL1, theL2, theP1, theP2, theP3, 0.01)) {
1261     return NULL;
1262   }
1263
1264   GEOMImpl_IPipeTShape aData(aFunction);
1265
1266   aData.SetR1(theR1);
1267   aData.SetW1(theW1);
1268   aData.SetL1(theL1);
1269   aData.SetR2(theR2);
1270   aData.SetW2(theW2);
1271   aData.SetL2(theL2);
1272   aData.SetHexMesh(theHexMesh);
1273
1274   //Compute the resulting value
1275   try {
1276 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
1277     OCC_CATCH_SIGNALS;
1278 #endif
1279     if (!GetSolver()->ComputeFunction(aFunction)) {
1280       SetErrorCode("TShape driver failed");
1281       return NULL;
1282     }
1283   } catch (Standard_Failure) {
1284     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1285     SetErrorCode(aFail->GetMessageString());
1286     return NULL;
1287   }
1288
1289   if (theHexMesh) {
1290     if (!MakePipeTShapePartition(aShape, theR1, theW1, theL1, theR2, theW2, theL2))
1291       return NULL;
1292     if (!MakePipeTShapeMirrorAndGlue(aShape, theR1, theW1, theL1, theR2, theW2, theL2))
1293       return NULL;
1294   }
1295
1296   TopoDS_Shape Te = aShape->GetValue();
1297
1298   // Set Position
1299   gp_Trsf aTrsf = GetPositionTrsf(theL1, theL2, theP1, theP2, theP3);
1300   BRepBuilderAPI_Transform aTransformation(Te, aTrsf, Standard_False);
1301   TopoDS_Shape aTrsf_Shape = aTransformation.Shape();
1302   aFunction->SetValue(aTrsf_Shape);
1303   Handle(TColStd_HSequenceOfTransient) aSeq = new TColStd_HSequenceOfTransient;
1304   aSeq->Append(aShape);
1305
1306   if (theHexMesh) {
1307     //
1308     // Get the groups: BEGIN
1309     //
1310     try {
1311       if (!MakeGroups(aShape,TSHAPE_BASIC, theR1, theW1, theL1, theR2, theW2, theL2, aSeq, aTrsf)) {
1312         return NULL;
1313       }
1314     }
1315     catch (Standard_Failure) {
1316       Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1317       SetErrorCode(aFail->GetMessageString());
1318       return NULL;
1319     }
1320
1321     TCollection_AsciiString aListRes, anEntry;
1322     // Iterate over the sequence aSeq
1323     Standard_Integer aNbGroups = aSeq->Length();
1324     Standard_Integer i = 2;
1325     for (; i <= aNbGroups; i++) {
1326       Handle(Standard_Transient) anItem = aSeq->Value(i);
1327       if (anItem.IsNull()) continue;
1328       Handle(GEOM_Object) aGroup = Handle(GEOM_Object)::DownCast(anItem);
1329       if (aGroup.IsNull()) continue;
1330       //Make a Python command
1331       TDF_Tool::Entry(aGroup->GetEntry(), anEntry);
1332       aListRes += anEntry + ", ";
1333     }
1334
1335     aListRes.Trunc(aListRes.Length() - 2);
1336
1337     //Make a Python command
1338     GEOM::TPythonDump(aFunction)
1339       << "[" << aShape << ", " << aListRes.ToCString() << "] = geompy.MakePipeTShape("
1340       << theR1 << ", " << theW1 << ", " << theL1 << ", " << theR2 << ", " << theW2 << ", " << theL2 << ", "
1341       << theHexMesh << ", " << theP1 << ", " << theP2 << ", " << theP3 << ")";
1342   }
1343   //
1344   // Get the groups: END
1345   //
1346
1347   else {
1348     //Make a Python command
1349     GEOM::TPythonDump(aFunction)
1350       << "[" << aShape << "] = geompy.MakePipeTShape(" << theR1 << ", " << theW1 << ", "
1351       << theL1 << ", " << theR2 << ", " << theW2 << ", " << theL2 << ", " << theHexMesh << ", " << theP1
1352       << ", " << theP2 << ", " << theP3 << ")";
1353   }
1354
1355   SetErrorCode(OK);
1356
1357   return aSeq;
1358 }
1359
1360 //=============================================================================
1361 /*!
1362  *  MakePipeTShapeChamfer
1363  *  Create a T-shape object with specified caracteristics for the main and
1364  *  the incident pipes (radius, width, half-length). A chamfer is created
1365  *  on the junction of the pipes.
1366  *  Center of the shape is (0,0,0). The main plane of the T-shape is XOY.
1367  *  \param theR1 Internal radius of main pipe
1368  *  \param theW1 Width of main pipe
1369  *  \param theL1 Half-length of main pipe
1370  *  \param theR2 Internal radius of incident pipe (R2 < R1)
1371  *  \param theW2 Width of incident pipe (R2+W2 < R1+W1)
1372  *  \param theL2 Half-length of incident pipe
1373  *  \param theH Height of chamfer.
1374  *  \param theW Width of chamfer.
1375  *  \param theHexMesh Boolean indicating if shape is prepared for hex mesh
1376  *  \return List of GEOM_Objects, containing the created shape and propagation groups.
1377  */
1378 //=============================================================================
1379 Handle(TColStd_HSequenceOfTransient)
1380 GEOMImpl_IAdvancedOperations::MakePipeTShapeChamfer(double theR1, double theW1, double theL1,
1381                                                     double theR2, double theW2, double theL2,
1382                                                     double theH, double theW,
1383                                                     bool theHexMesh)
1384 {
1385   SetErrorCode(KO);
1386   //Add a new object
1387   Handle(GEOM_Object) aShape = GetEngine()->AddObject(GetDocID(), GEOM_TSHAPE);
1388   //Add a new shape function with parameters
1389   Handle(GEOM_Function) aFunction = aShape->AddFunction(GEOMImpl_PipeTShapeDriver::GetID(), TSHAPE_CHAMFER);
1390   if (aFunction.IsNull()) return NULL;
1391
1392   //Check if the function is set correctly
1393   if (aFunction->GetDriverGUID() != GEOMImpl_PipeTShapeDriver::GetID()) return NULL;
1394
1395   GEOMImpl_IPipeTShape aData(aFunction);
1396
1397   aData.SetR1(theR1);
1398   aData.SetW1(theW1);
1399   aData.SetL1(theL1);
1400   aData.SetR2(theR2);
1401   aData.SetW2(theW2);
1402   aData.SetL2(theL2);
1403   aData.SetH(theH);
1404   aData.SetW(theW);
1405   aData.SetHexMesh(theHexMesh);
1406
1407   //Compute the resulting value
1408   try {
1409 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
1410     OCC_CATCH_SIGNALS;
1411 #endif
1412     if (!GetSolver()->ComputeFunction(aFunction)) {
1413       SetErrorCode("TShape driver failed");
1414       return NULL;
1415     }
1416   } catch (Standard_Failure) {
1417     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1418     SetErrorCode(aFail->GetMessageString());
1419     return NULL;
1420   }
1421
1422   // BEGIN of chamfer
1423   TopoDS_Shape aShapeShape = aShape->GetValue();
1424   TopTools_IndexedMapOfShape anEdgesIndices;
1425   TopExp::MapShapes(aShapeShape, anEdgesIndices);
1426   // Common edges on external cylinders
1427   Handle(GEOM_Object) box_e;
1428   if (theHexMesh) {
1429     box_e = my3DPrimOperations->MakeBoxDXDYDZ(theR2+theW2, theR2+theW2, theR1+theW1);
1430   }
1431   else {
1432     box_e = my3DPrimOperations->MakeBoxDXDYDZ(2*(theR2+theW2), 2*(theR2+theW2), theR1+theW1);
1433   }
1434   box_e->GetLastFunction()->SetDescription("");
1435   box_e = myTransformOperations->TranslateDXDYDZ(box_e, -(theR2+theW2), -(theR2+theW2), 0);
1436   box_e->GetLastFunction()->SetDescription("");
1437
1438   Handle(TColStd_HSequenceOfInteger) edges_e =
1439     myShapesOperations->GetShapesOnBoxIDs(box_e, aShape, TopAbs_EDGE, GEOMAlgo_ST_IN);
1440   box_e->GetLastFunction()->SetDescription("");
1441
1442   if (edges_e.IsNull() || edges_e->Length() == 0) {
1443     SetErrorCode("External edges not found");
1444     return false;
1445   }
1446   int nbEdgesInChamfer = 0;
1447   std::list<int> theEdges;
1448   for (int i=1; i<=edges_e->Length();i++) {
1449     int edgeID = edges_e->Value(i);
1450     TopoDS_Shape theEdge = anEdgesIndices.FindKey(edgeID);
1451     TopExp_Explorer Ex(theEdge,TopAbs_VERTEX);
1452     int iv=0;
1453     while (Ex.More()) {
1454       iv ++;
1455       gp_Pnt aPt = BRep_Tool::Pnt(TopoDS::Vertex(Ex.Current()));
1456       if (Abs(aPt.Z() - (theR1+theW1)) <= Precision::Confusion()) {
1457         nbEdgesInChamfer ++;
1458         theEdges.push_back(edgeID);
1459       }
1460       Ex.Next();
1461     }
1462     if (theHexMesh && nbEdgesInChamfer == 1)
1463       break;
1464   }
1465   Handle(GEOM_Object) aChamfer;
1466   try {
1467     aChamfer = myLocalOperations->MakeChamferEdges(aShape, theW, theH, theEdges);
1468   }
1469   catch (Standard_Failure) {
1470     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1471     SetErrorCode(aFail->GetMessageString());
1472     return NULL;
1473   }
1474   if (aChamfer.IsNull()) {
1475     SetErrorCode("Chamfer can not be computed on the given shape with the given parameters");
1476     return NULL;
1477   }
1478   aChamfer->GetLastFunction()->SetDescription("");
1479
1480   TopoDS_Shape aChamferShape = aChamfer->GetValue();
1481   aFunction->SetValue(aChamferShape);
1482   // END of chamfer
1483
1484   //   bool doMesh = false;
1485   if (theHexMesh) {
1486     //        doMesh = true;
1487     if (!MakePipeTShapePartition(aShape, theR1, theW1, theL1, theR2, theW2, theL2, theH, theW, 0, false)) {
1488       MESSAGE("PipeTShape partition failed");
1489       //            doMesh = false;
1490       return NULL;
1491     }
1492     if (!MakePipeTShapeMirrorAndGlue(aShape, theR1, theW1, theL1, theR2, theW2, theL2)) {
1493       MESSAGE("PipeTShape mirrors and glue failed");
1494       //          doMesh = false;
1495       return NULL;
1496     }
1497   }
1498
1499   Handle(TColStd_HSequenceOfTransient) aSeq = new TColStd_HSequenceOfTransient;
1500   aSeq->Append(aShape);
1501
1502   //    if (doMesh) {
1503   if (theHexMesh) {
1504     //
1505     //         Get the groups: BEGIN
1506     //
1507     //if (!MakeGroups(aShape, TSHAPE_CHAMFER, theR1, theW1, theL1, theR2, theW2, theL2, aSeq, gp_Trsf())) {
1508     //  //Make a Python command
1509     //  GEOM::TPythonDump(aFunction)
1510     //    << "[" << aShape << "] = geompy.MakePipeTShapeChamfer(" << theR1 << ", " << theW1
1511     //    << ", " << theL1 << ", " << theR2 << ", " << theW2 << ", " << theL2 << ", " << theH << ", " << theW
1512     //    << ", " << theHexMesh << ")";
1513     //}
1514     //else {
1515     try {
1516       if (!MakeGroups(aShape, TSHAPE_CHAMFER, theR1, theW1, theL1, theR2, theW2, theL2, aSeq, gp_Trsf()))
1517         return NULL;
1518     }
1519     catch (Standard_Failure) {
1520       Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1521       SetErrorCode(aFail->GetMessageString());
1522       return NULL;
1523     }
1524
1525     TCollection_AsciiString aListRes, anEntry;
1526     // Iterate over the sequence aSeq
1527     Standard_Integer aNbGroups = aSeq->Length();
1528     Standard_Integer i = 2;
1529     for (; i <= aNbGroups; i++) {
1530       Handle(Standard_Transient) anItem = aSeq->Value(i);
1531       if (anItem.IsNull()) continue;
1532       Handle(GEOM_Object) aGroup = Handle(GEOM_Object)::DownCast(anItem);
1533       if (aGroup.IsNull()) continue;
1534       //Make a Python command
1535       TDF_Tool::Entry(aGroup->GetEntry(), anEntry);
1536       aListRes += anEntry + ", ";
1537     }
1538
1539     aListRes.Trunc(aListRes.Length() - 2);
1540
1541     //Make a Python command
1542     GEOM::TPythonDump(aFunction)
1543       << "[" << aShape << ", " << aListRes.ToCString()
1544       << "] = geompy.MakePipeTShapeChamfer(" << theR1 << ", " << theW1 << ", " << theL1 << ", " << theR2
1545       << ", " << theW2 << ", " << theL2 << ", " << theH << ", " << theW << ", " << theHexMesh << ")";
1546     //}
1547   }
1548   //
1549   //     Get the groups: END
1550   //
1551   else {
1552     //Make a Python command
1553     GEOM::TPythonDump(aFunction)
1554       << "[" << aShape << "] = geompy.MakePipeTShapeChamfer(" << theR1 << ", " << theW1
1555       << ", " << theL1 << ", " << theR2 << ", " << theW2 << ", " << theL2 << ", " << theH << ", " << theW
1556       << ", " << theHexMesh << ")";
1557   }
1558
1559   SetErrorCode(OK);
1560
1561   return aSeq;
1562 }
1563
1564 //=============================================================================
1565 /*!
1566  *  MakePipeTShapeChamferWithPosition
1567  *  Create a T-shape object with specified caracteristics for the main and
1568  *  the incident pipes (radius, width, half-length). A chamfer is created
1569  *  on the junction of the pipes.
1570  *  The extremities of the main pipe are located on junctions points P1 and P2.
1571  *  The extremity of the incident pipe is located on junction point P3.
1572  *  \param theR1 Internal radius of main pipe
1573  *  \param theW1 Width of main pipe
1574  *  \param theL1 Half-length of main pipe
1575  *  \param theR2 Internal radius of incident pipe (R2 < R1)
1576  *  \param theW2 Width of incident pipe (R2+W2 < R1+W1)
1577  *  \param theL2 Half-length of incident pipe
1578  *  \param theH Height of chamfer.
1579  *  \param theW Width of chamfer.
1580  *  \param theHexMesh Boolean indicating if shape is prepared for hex mesh
1581  *  \param theP1 1st junction point of main pipe
1582  *  \param theP2 2nd junction point of main pipe
1583  *  \param theP3 Junction point of incident pipe
1584  *  \return List of GEOM_Objects, containing the created shape and propagation groups.
1585  */
1586 //=============================================================================
1587 Handle(TColStd_HSequenceOfTransient)
1588 GEOMImpl_IAdvancedOperations::MakePipeTShapeChamferWithPosition(double theR1, double theW1, double theL1,
1589                                                                 double theR2, double theW2, double theL2,
1590                                                                 double theH, double theW,
1591                                                                 bool theHexMesh,
1592                                                                 Handle(GEOM_Object) theP1,
1593                                                                 Handle(GEOM_Object) theP2,
1594                                                                 Handle(GEOM_Object) theP3)
1595 {
1596   SetErrorCode(KO);
1597   //Add a new object
1598   Handle(GEOM_Object) aShape = GetEngine()->AddObject(GetDocID(), GEOM_TSHAPE);
1599   //Add a new shape function with parameters
1600   Handle(GEOM_Function) aFunction = aShape->AddFunction(GEOMImpl_PipeTShapeDriver::GetID(), TSHAPE_CHAMFER);
1601   if (aFunction.IsNull()) return NULL;
1602
1603   //Check if the function is set correctly
1604   if (aFunction->GetDriverGUID() != GEOMImpl_PipeTShapeDriver::GetID()) return NULL;
1605
1606   // Check new position
1607   if (!CheckCompatiblePosition(theL1, theL2, theP1, theP2, theP3, 0.01)) {
1608     return NULL;
1609   }
1610
1611   GEOMImpl_IPipeTShape aData(aFunction);
1612
1613   aData.SetR1(theR1);
1614   aData.SetW1(theW1);
1615   aData.SetL1(theL1);
1616   aData.SetR2(theR2);
1617   aData.SetW2(theW2);
1618   aData.SetL2(theL2);
1619   aData.SetH(theH);
1620   aData.SetW(theW);
1621   aData.SetHexMesh(theHexMesh);
1622
1623   //Compute the resulting value
1624   try {
1625 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
1626     OCC_CATCH_SIGNALS;
1627 #endif
1628     if (!GetSolver()->ComputeFunction(aFunction)) {
1629       SetErrorCode("TShape driver failed");
1630       return NULL;
1631     }
1632   } catch (Standard_Failure) {
1633     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1634     SetErrorCode(aFail->GetMessageString());
1635     return NULL;
1636   }
1637
1638   // BEGIN of chamfer
1639   TopoDS_Shape aShapeShape = aShape->GetValue();
1640   TopTools_IndexedMapOfShape anEdgesIndices;
1641   TopExp::MapShapes(aShapeShape, anEdgesIndices);
1642   // Common edges on external cylinders
1643   Handle(GEOM_Object) box_e;
1644   if (theHexMesh) {
1645     box_e = my3DPrimOperations->MakeBoxDXDYDZ(theR2+theW2, theR2+theW2, theR1+theW1);
1646   }
1647   else {
1648     box_e = my3DPrimOperations->MakeBoxDXDYDZ(2*(theR2+theW2), 2*(theR2+theW2), theR1+theW1);
1649   }
1650   box_e->GetLastFunction()->SetDescription("");
1651   box_e = myTransformOperations->TranslateDXDYDZ(box_e, -(theR2+theW2), -(theR2+theW2), 0);
1652   box_e->GetLastFunction()->SetDescription("");
1653
1654   Handle(TColStd_HSequenceOfInteger) edges_e =
1655     myShapesOperations->GetShapesOnBoxIDs(box_e, aShape, TopAbs_EDGE, GEOMAlgo_ST_IN);
1656   box_e->GetLastFunction()->SetDescription("");
1657
1658   if (edges_e.IsNull() || edges_e->Length() == 0) {
1659     SetErrorCode("External edges not found");
1660     return false;
1661   }
1662   int nbEdgesInChamfer = 0;
1663   std::list<int> theEdges;
1664   for (int i=1; i<=edges_e->Length();i++) {
1665     int edgeID = edges_e->Value(i);
1666     TopoDS_Shape theEdge = anEdgesIndices.FindKey(edgeID);
1667     TopExp_Explorer Ex(theEdge,TopAbs_VERTEX);
1668     while (Ex.More()) {
1669       gp_Pnt aPt = BRep_Tool::Pnt(TopoDS::Vertex(Ex.Current()));
1670       if (Abs(aPt.Z() - (theR1+theW1)) <= Precision::Confusion()) {
1671         nbEdgesInChamfer ++;
1672         theEdges.push_back(edgeID);
1673       }
1674       Ex.Next();
1675     }
1676     if (theHexMesh && nbEdgesInChamfer == 1)
1677       break;
1678   }
1679   Handle(GEOM_Object) aChamfer;
1680   try {
1681     aChamfer = myLocalOperations->MakeChamferEdges(aShape, theW, theH, theEdges);
1682   }
1683   catch (Standard_Failure) {
1684     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1685     SetErrorCode(aFail->GetMessageString());
1686     return NULL;
1687   }
1688   if (aChamfer.IsNull()) {
1689     SetErrorCode("Chamfer can not be computed on the given shape with the given parameters");
1690     return NULL;
1691   }
1692   aChamfer->GetLastFunction()->SetDescription("");
1693
1694   TopoDS_Shape aChamferShape = aChamfer->GetValue();
1695   aFunction->SetValue(aChamferShape);
1696   // END of chamfer
1697
1698   if (theHexMesh) {
1699     if (!MakePipeTShapePartition(aShape, theR1, theW1, theL1, theR2, theW2, theL2, theH, theW, 0, false))
1700       return NULL;
1701     if (!MakePipeTShapeMirrorAndGlue(aShape, theR1, theW1, theL1, theR2, theW2, theL2))
1702       return NULL;
1703   }
1704
1705   TopoDS_Shape Te = aShape->GetValue();
1706
1707   // Set Position
1708   gp_Trsf aTrsf = GetPositionTrsf(theL1, theL2, theP1, theP2, theP3);
1709   BRepBuilderAPI_Transform aTransformation(Te, aTrsf, Standard_False);
1710   TopoDS_Shape aTrsf_Shape = aTransformation.Shape();
1711   aFunction->SetValue(aTrsf_Shape);
1712   Handle(TColStd_HSequenceOfTransient) aSeq = new TColStd_HSequenceOfTransient;
1713   aSeq->Append(aShape);
1714   if (theHexMesh) {
1715     /*
1716      * Get the groups: BEGIN
1717      */
1718     try {
1719       if (!MakeGroups(aShape, TSHAPE_CHAMFER, theR1, theW1, theL1, theR2, theW2, theL2, aSeq, aTrsf))
1720         return NULL;
1721     }
1722     catch (Standard_Failure) {
1723       Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1724       SetErrorCode(aFail->GetMessageString());
1725       return NULL;
1726     }
1727
1728     TCollection_AsciiString aListRes, anEntry;
1729     // Iterate over the sequence aSeq
1730     Standard_Integer aNbGroups = aSeq->Length();
1731     Standard_Integer i = 2;
1732     for (; i <= aNbGroups; i++) {
1733       Handle(Standard_Transient) anItem = aSeq->Value(i);
1734       if (anItem.IsNull()) continue;
1735       Handle(GEOM_Object) aGroup = Handle(GEOM_Object)::DownCast(anItem);
1736       if (aGroup.IsNull()) continue;
1737       //Make a Python command
1738       TDF_Tool::Entry(aGroup->GetEntry(), anEntry);
1739       aListRes += anEntry + ", ";
1740     }
1741
1742     aListRes.Trunc(aListRes.Length() - 2);
1743
1744     //Make a Python command
1745     GEOM::TPythonDump(aFunction)
1746       << "[" << aShape << ", " << aListRes.ToCString()
1747       << "] = geompy.MakePipeTShapeChamfer(" << theR1 << ", " << theW1 << ", " << theL1 << ", " << theR2
1748       << ", " << theW2 << ", " << theL2 << ", " << theH << ", " << theW << ", " << theHexMesh << ", "
1749       << theP1 << ", " << theP2 << ", " << theP3 << ")";
1750   }
1751   /*
1752    * Get the groups: END
1753    */
1754   else {
1755     //Make a Python command
1756     GEOM::TPythonDump(aFunction)
1757       << "[" << aShape << "] = geompy.MakePipeTShapeChamfer(" << theR1 << ", " << theW1
1758       << ", " << theL1 << ", " << theR2 << ", " << theW2 << ", " << theL2 << ", " << theH << ", " << theW
1759       << ", " << theHexMesh << ", " << theP1 << ", " << theP2 << ", " << theP3 << ")";
1760   }
1761
1762   SetErrorCode(OK);
1763
1764   return aSeq;
1765 }
1766
1767 //=============================================================================
1768 /*!
1769  *  MakePipeTShapeFillet
1770  *  Create a T-shape object with specified caracteristics for the main and
1771  *  the incident pipes (radius, width, half-length). A fillet is created
1772  *  on the junction of the pipes.
1773  *  Center of the shape is (0,0,0). The main plane of the T-shape is XOY.
1774  *  \param theR1 Internal radius of main pipe
1775  *  \param theW1 Width of main pipe
1776  *  \param theL1 Half-length of main pipe
1777  *  \param theR2 Internal radius of incident pipe (R2 < R1)
1778  *  \param theW2 Width of incident pipe (R2+W2 < R1+W1)
1779  *  \param theL2 Half-length of incident pipe
1780  *  \param theRF Radius of curvature of fillet.
1781  *  \param theHexMesh Boolean indicating if shape is prepared for hex mesh
1782  *  \return List of GEOM_Objects, containing the created shape and propagation groups.
1783  */
1784 //=============================================================================
1785 Handle(TColStd_HSequenceOfTransient)
1786 GEOMImpl_IAdvancedOperations::MakePipeTShapeFillet(double theR1, double theW1, double theL1,
1787                                                    double theR2, double theW2, double theL2,
1788                                                    double theRF, bool theHexMesh)
1789 {
1790   SetErrorCode(KO);
1791   //Add a new object
1792   Handle(GEOM_Object) aShape = GetEngine()->AddObject(GetDocID(), GEOM_TSHAPE);
1793   //Add a new shape function with parameters
1794   Handle(GEOM_Function) aFunction = aShape->AddFunction(GEOMImpl_PipeTShapeDriver::GetID(), TSHAPE_FILLET);
1795   if (aFunction.IsNull()) return NULL;
1796
1797   //Check if the function is set correctly
1798   if (aFunction->GetDriverGUID() != GEOMImpl_PipeTShapeDriver::GetID()) return NULL;
1799
1800   GEOMImpl_IPipeTShape aData(aFunction);
1801
1802   aData.SetR1(theR1);
1803   aData.SetW1(theW1);
1804   aData.SetL1(theL1);
1805   aData.SetR2(theR2);
1806   aData.SetW2(theW2);
1807   aData.SetL2(theL2);
1808   aData.SetRF(theRF);
1809   aData.SetHexMesh(theHexMesh);
1810
1811   //Compute the resulting value
1812   try {
1813 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
1814     OCC_CATCH_SIGNALS;
1815 #endif
1816     if (!GetSolver()->ComputeFunction(aFunction)) {
1817       SetErrorCode("TShape driver failed");
1818       return NULL;
1819     }
1820   } catch (Standard_Failure) {
1821     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1822     SetErrorCode(aFail->GetMessageString());
1823     return NULL;
1824   }
1825
1826   // BEGIN of fillet
1827   TopoDS_Shape aShapeShape = aShape->GetValue();
1828   TopTools_IndexedMapOfShape anEdgesIndices;
1829   TopExp::MapShapes(aShapeShape, anEdgesIndices);
1830   // Common edges on external cylinders
1831   Handle(GEOM_Object) box_e;
1832   if (theHexMesh) {
1833     box_e = my3DPrimOperations->MakeBoxDXDYDZ(theR2+theW2, theR2+theW2, theR1+theW1);
1834   }
1835   else {
1836     box_e = my3DPrimOperations->MakeBoxDXDYDZ(2*(theR2+theW2), 2*(theR2+theW2), theR1+theW1);
1837   }
1838   box_e->GetLastFunction()->SetDescription("");
1839   box_e = myTransformOperations->TranslateDXDYDZ(box_e, -(theR2+theW2), -(theR2+theW2), 0);
1840   box_e->GetLastFunction()->SetDescription("");
1841
1842   Handle(TColStd_HSequenceOfInteger) edges_e =
1843     myShapesOperations->GetShapesOnBoxIDs(box_e, aShape, TopAbs_EDGE, GEOMAlgo_ST_IN);
1844   box_e->GetLastFunction()->SetDescription("");
1845
1846   if (edges_e.IsNull() || edges_e->Length() == 0) {
1847     SetErrorCode("External edges not found");
1848     return false;
1849   }
1850   int nbEdgesInFillet = 0;
1851   std::list<int> theEdges;
1852   for (int i=1; i<=edges_e->Length();i++) {
1853     int edgeID = edges_e->Value(i);
1854     TopoDS_Shape theEdge = anEdgesIndices.FindKey(edgeID);
1855     TopExp_Explorer Ex(theEdge,TopAbs_VERTEX);
1856     while (Ex.More()) {
1857       gp_Pnt aPt = BRep_Tool::Pnt(TopoDS::Vertex(Ex.Current()));
1858       if (Abs(aPt.Z() - (theR1+theW1)) <= Precision::Confusion()) {
1859         nbEdgesInFillet ++;
1860         theEdges.push_back(edgeID);
1861       }
1862       Ex.Next();
1863     }
1864     if (theHexMesh && nbEdgesInFillet == 1)
1865       break;
1866   }
1867
1868   Handle(GEOM_Object) aFillet;
1869   try {
1870     aFillet = myLocalOperations->MakeFilletEdges(aShape, theRF, theEdges);
1871   }
1872   catch (Standard_Failure) {
1873     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1874     SetErrorCode(aFail->GetMessageString());
1875     return NULL;
1876   }
1877   if (aFillet.IsNull()) {
1878     //SetErrorCode("Fillet can not be computed on the given shape with the given parameters");
1879     SetErrorCode(myLocalOperations->GetErrorCode());
1880     return NULL;
1881   }
1882   aFillet->GetLastFunction()->SetDescription("");
1883
1884   TopoDS_Shape aFilletShape = aFillet->GetValue();
1885   aFunction->SetValue(aFilletShape);
1886   // END of fillet
1887
1888   // BEGIN: Limit tolerances (debug)
1889   Handle(GEOM_Object) aCorr1 = myHealingOperations->LimitTolerance(aShape, 1e-07);
1890   TopoDS_Shape aCorr1Shape = aCorr1->GetValue();
1891   aShape->GetLastFunction()->SetValue(aCorr1Shape);
1892   aCorr1->GetLastFunction()->SetDescription("");
1893   // END: Limit tolerances (debug)
1894
1895   if (theHexMesh) {
1896     if (!MakePipeTShapePartition(aShape, theR1, theW1, theL1, theR2, theW2, theL2, 0, 0, theRF, false))
1897       return NULL;
1898     if (!MakePipeTShapeMirrorAndGlue(aShape, theR1, theW1, theL1, theR2, theW2, theL2))
1899       return NULL;
1900   }
1901
1902   Handle(TColStd_HSequenceOfTransient) aSeq = new TColStd_HSequenceOfTransient;
1903   aSeq->Append(aShape);
1904   if (theHexMesh) {
1905     /*
1906      * Get the groups: BEGIN
1907      */
1908     try {
1909       if (!MakeGroups(aShape, TSHAPE_FILLET, theR1, theW1, theL1, theR2, theW2, theL2, aSeq, gp_Trsf()))
1910         return NULL;
1911     }
1912     catch (Standard_Failure) {
1913       Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1914       SetErrorCode(aFail->GetMessageString());
1915       return NULL;
1916     }
1917
1918     TCollection_AsciiString aListRes, anEntry;
1919     // Iterate over the sequence aSeq
1920     Standard_Integer aNbGroups = aSeq->Length();
1921     Standard_Integer i = 2;
1922     for (; i <= aNbGroups; i++) {
1923       Handle(Standard_Transient) anItem = aSeq->Value(i);
1924       if (anItem.IsNull()) continue;
1925       Handle(GEOM_Object) aGroup = Handle(GEOM_Object)::DownCast(anItem);
1926       if (aGroup.IsNull()) continue;
1927       //Make a Python command
1928       TDF_Tool::Entry(aGroup->GetEntry(), anEntry);
1929       aListRes += anEntry + ", ";
1930     }
1931
1932     aListRes.Trunc(aListRes.Length() - 2);
1933
1934     //Make a Python command
1935     GEOM::TPythonDump(aFunction)
1936       << "[" << aShape << ", " << aListRes.ToCString()
1937       << "] = geompy.MakePipeTShapeFillet(" << theR1 << ", " << theW1 << ", " << theL1 << ", " << theR2
1938       << ", " << theW2 << ", " << theL2 << ", " << theRF << ", " << theHexMesh << ")";
1939   }
1940   /*
1941    * Get the groups: END
1942    */
1943   else {
1944     //Make a Python command
1945     GEOM::TPythonDump(aFunction)
1946       << "[" << aShape << "] = geompy.MakePipeTShapeFillet(" << theR1 << ", " << theW1
1947       << ", " << theL1 << ", " << theR2 << ", " << theW2 << ", " << theL2 << ", " << theRF << ", "
1948       << theHexMesh << ")";
1949   }
1950
1951   SetErrorCode(OK);
1952
1953   return aSeq;
1954 }
1955
1956 //=============================================================================
1957 /*!
1958  *  MakePipeTShapeFilletWithPosition
1959  *  Create a T-shape object with specified caracteristics for the main and
1960  *  the incident pipes (radius, width, half-length). A fillet is created
1961  *  on the junction of the pipes.
1962  *  The extremities of the main pipe are located on junctions points P1 and P2.
1963  *  The extremity of the incident pipe is located on junction point P3.
1964  *  \param theR1 Internal radius of main pipe
1965  *  \param theW1 Width of main pipe
1966  *  \param theL1 Half-length of main pipe
1967  *  \param theR2 Internal radius of incident pipe (R2 < R1)
1968  *  \param theW2 Width of incident pipe (R2+W2 < R1+W1)
1969  *  \param theL2 Half-length of incident pipe
1970  *  \param theRF Radius of curvature of fillet
1971  *  \param theHexMesh Boolean indicating if shape is prepared for hex mesh
1972  *  \param theP1 1st junction point of main pipe
1973  *  \param theP2 2nd junction point of main pipe
1974  *  \param theP3 Junction point of incident pipe
1975  *  \return List of GEOM_Objects, containing the created shape and propagation groups.
1976  */
1977 //=============================================================================
1978 Handle(TColStd_HSequenceOfTransient)
1979 GEOMImpl_IAdvancedOperations::MakePipeTShapeFilletWithPosition(double theR1, double theW1, double theL1,
1980                                                                double theR2, double theW2, double theL2,
1981                                                                double theRF, bool theHexMesh,
1982                                                                Handle(GEOM_Object) theP1,
1983                                                                Handle(GEOM_Object) theP2,
1984                                                                Handle(GEOM_Object) theP3)
1985 {
1986   SetErrorCode(KO);
1987   //Add a new object
1988   Handle(GEOM_Object) aShape = GetEngine()->AddObject(GetDocID(), GEOM_TSHAPE);
1989   //Add a new shape function with parameters
1990   Handle(GEOM_Function) aFunction = aShape->AddFunction(GEOMImpl_PipeTShapeDriver::GetID(), TSHAPE_FILLET);
1991   if (aFunction.IsNull()) return NULL;
1992
1993   //Check if the function is set correctly
1994   if (aFunction->GetDriverGUID() != GEOMImpl_PipeTShapeDriver::GetID()) return NULL;
1995
1996   // Check new position
1997   if (!CheckCompatiblePosition(theL1, theL2, theP1, theP2, theP3, 0.01)) {
1998     return NULL;
1999   }
2000
2001   GEOMImpl_IPipeTShape aData(aFunction);
2002
2003   aData.SetR1(theR1);
2004   aData.SetW1(theW1);
2005   aData.SetL1(theL1);
2006   aData.SetR2(theR2);
2007   aData.SetW2(theW2);
2008   aData.SetL2(theL2);
2009   aData.SetRF(theRF);
2010   aData.SetHexMesh(theHexMesh);
2011
2012   //Compute the resulting value
2013   try {
2014 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
2015     OCC_CATCH_SIGNALS;
2016 #endif
2017     if (!GetSolver()->ComputeFunction(aFunction)) {
2018       SetErrorCode("TShape driver failed");
2019       return NULL;
2020     }
2021   } catch (Standard_Failure) {
2022     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
2023     SetErrorCode(aFail->GetMessageString());
2024     return NULL;
2025   }
2026
2027   // BEGIN of fillet
2028   TopoDS_Shape aShapeShape = aShape->GetValue();
2029   TopTools_IndexedMapOfShape anEdgesIndices;
2030   TopExp::MapShapes(aShapeShape, anEdgesIndices);
2031   // Common edges on external cylinders
2032   Handle(GEOM_Object) box_e;
2033   if (theHexMesh) {
2034     box_e = my3DPrimOperations->MakeBoxDXDYDZ(theR2+theW2, theR2+theW2, theR1+theW1);
2035   }
2036   else {
2037     box_e = my3DPrimOperations->MakeBoxDXDYDZ(2*(theR2+theW2), 2*(theR2+theW2), theR1+theW1);
2038   }
2039   box_e->GetLastFunction()->SetDescription("");
2040   box_e = myTransformOperations->TranslateDXDYDZ(box_e, -(theR2+theW2), -(theR2+theW2), 0);
2041   box_e->GetLastFunction()->SetDescription("");
2042
2043   Handle(TColStd_HSequenceOfInteger) edges_e =
2044     myShapesOperations->GetShapesOnBoxIDs(box_e, aShape, TopAbs_EDGE, GEOMAlgo_ST_IN);
2045   box_e->GetLastFunction()->SetDescription("");
2046
2047   if (edges_e.IsNull() || edges_e->Length() == 0) {
2048     SetErrorCode("External edges not found");
2049     return false;
2050   }
2051   int nbEdgesInFillet = 0;
2052   std::list<int> theEdges;
2053   for (int i=1; i<=edges_e->Length();i++) {
2054     int edgeID = edges_e->Value(i);
2055     TopoDS_Shape theEdge = anEdgesIndices.FindKey(edgeID);
2056     TopExp_Explorer Ex(theEdge,TopAbs_VERTEX);
2057     while (Ex.More()) {
2058       gp_Pnt aPt = BRep_Tool::Pnt(TopoDS::Vertex(Ex.Current()));
2059       if (Abs(aPt.Z() - (theR1+theW1)) <= Precision::Confusion()) {
2060         nbEdgesInFillet ++;
2061         theEdges.push_back(edgeID);
2062       }
2063       Ex.Next();
2064     }
2065     if (theHexMesh && nbEdgesInFillet == 1)
2066       break;
2067   }
2068
2069   Handle(GEOM_Object) aFillet;
2070   try {
2071     aFillet = myLocalOperations->MakeFilletEdges(aShape, theRF, theEdges);
2072   }
2073   catch (Standard_Failure) {
2074     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
2075     SetErrorCode(aFail->GetMessageString());
2076     return NULL;
2077   }
2078   if (aFillet.IsNull()) {
2079     SetErrorCode("Fillet can not be computed on the given shape with the given parameters");
2080     return NULL;
2081   }
2082   aFillet->GetLastFunction()->SetDescription("");
2083
2084   TopoDS_Shape aFilletShape = aFillet->GetValue();
2085   aFunction->SetValue(aFilletShape);
2086   // END of fillet
2087
2088   // BEGIN: Limit tolerances (debug)
2089   Handle(GEOM_Object) aCorr1 = myHealingOperations->LimitTolerance(aShape, 1e-07);
2090   TopoDS_Shape aCorr1Shape = aCorr1->GetValue();
2091   aShape->GetLastFunction()->SetValue(aCorr1Shape);
2092   aCorr1->GetLastFunction()->SetDescription("");
2093   // END: Limit tolerances (debug)
2094
2095   if (theHexMesh) {
2096     if (!MakePipeTShapePartition(aShape, theR1, theW1, theL1, theR2, theW2, theL2, 0, 0, theRF, false))
2097       return NULL;
2098     if (!MakePipeTShapeMirrorAndGlue(aShape, theR1, theW1, theL1, theR2, theW2, theL2))
2099       return NULL;
2100   }
2101
2102   TopoDS_Shape Te = aShape->GetValue();
2103
2104   // Set Position
2105   gp_Trsf aTrsf = GetPositionTrsf(theL1, theL2, theP1, theP2, theP3);
2106   BRepBuilderAPI_Transform aTransformation(Te, aTrsf, Standard_False);
2107   TopoDS_Shape aTrsf_Shape = aTransformation.Shape();
2108   aFunction->SetValue(aTrsf_Shape);
2109   Handle(TColStd_HSequenceOfTransient) aSeq = new TColStd_HSequenceOfTransient;
2110   aSeq->Append(aShape);
2111   if (theHexMesh) {
2112     /*
2113      * Get the groups: BEGIN
2114      */
2115     try {
2116       if (!MakeGroups(aShape, TSHAPE_FILLET, theR1, theW1, theL1, theR2, theW2, theL2, aSeq, aTrsf))
2117         return NULL;
2118     }
2119     catch (Standard_Failure) {
2120       Handle(Standard_Failure) aFail = Standard_Failure::Caught();
2121       SetErrorCode(aFail->GetMessageString());
2122       return NULL;
2123     }
2124
2125     TCollection_AsciiString aListRes, anEntry;
2126     // Iterate over the sequence aSeq
2127     Standard_Integer aNbGroups = aSeq->Length();
2128     Standard_Integer i = 2;
2129     for (; i <= aNbGroups; i++) {
2130       Handle(Standard_Transient) anItem = aSeq->Value(i);
2131       if (anItem.IsNull()) continue;
2132       Handle(GEOM_Object) aGroup = Handle(GEOM_Object)::DownCast(anItem);
2133       if (aGroup.IsNull()) continue;
2134       //Make a Python command
2135       TDF_Tool::Entry(aGroup->GetEntry(), anEntry);
2136       aListRes += anEntry + ", ";
2137     }
2138
2139     aListRes.Trunc(aListRes.Length() - 2);
2140
2141     //Make a Python command
2142     GEOM::TPythonDump(aFunction)
2143       << "[" << aShape << ", " << aListRes.ToCString()
2144       << "] = geompy.MakePipeTShapeFillet(" << theR1 << ", " << theW1 << ", " << theL1 << ", " << theR2
2145       << ", " << theW2 << ", " << theL2 << ", " << theRF << ", " << theHexMesh << ", " << theP1 << ", "
2146       << theP2 << ", " << theP3 << ")";
2147   }
2148   /*
2149    * Get the groups: END
2150    */
2151   else {
2152     //Make a Python command
2153     GEOM::TPythonDump(aFunction)
2154       << "[" << aShape << "] = geompy.MakePipeTShapeFillet(" << theR1 << ", " << theW1
2155       << ", " << theL1 << ", " << theR2 << ", " << theW2 << ", " << theL2 << ", " << theRF << ", "
2156       << theHexMesh << ", " << theP1 << ", " << theP2 << ", " << theP3 << ")";
2157   }
2158
2159   SetErrorCode(OK);
2160
2161   return aSeq;
2162 }
2163
2164 /*@@ insert new functions before this line @@ do not remove this line @@ do not remove this line @@*/