1 // Copyright (C) 2007-2012 CEA/DEN, EDF R&D, OPEN CASCADE
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.
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.
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
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
19 // File : GEOMImpl_IAdvancedOperations.cxx
20 // Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com)
22 #include <Standard_Stream.hxx>
24 #include "GEOMImpl_Types.hxx"
25 #include "GEOMImpl_IAdvancedOperations.hxx"
26 #include "GEOMImpl_IBasicOperations.hxx"
27 #include "GEOMImpl_IBooleanOperations.hxx"
28 #include "GEOMImpl_IShapesOperations.hxx"
29 #include "GEOMImpl_ITransformOperations.hxx"
30 #include "GEOMImpl_IBlocksOperations.hxx"
31 #include "GEOMImpl_I3DPrimOperations.hxx"
32 #include "GEOMImpl_ILocalOperations.hxx"
33 #include "GEOMImpl_IHealingOperations.hxx"
35 #include "GEOMImpl_Gen.hxx"
37 #include <Basics_OCCTVersion.hxx>
39 #include <utilities.h>
41 #include <Utils_ExceptHandlers.hxx>
43 #include "GEOM_Function.hxx"
44 #include "GEOM_PythonDump.hxx"
46 #include "GEOMImpl_PipeTShapeDriver.hxx"
47 #include "GEOMImpl_IPipeTShape.hxx"
48 #include <GEOMImpl_DividedDiskDriver.hxx>
49 #include <GEOMImpl_IDividedDisk.hxx>
50 // #include <GEOMImpl_DividedCylinderDriver.hxx>
51 // #include <GEOMImpl_IDividedCylinder.hxx>
52 /*@@ insert new functions before this line @@ do not remove this line @@ do not remove this line @@*/
55 #include <TopExp_Explorer.hxx>
57 #include <TopoDS_Vertex.hxx>
58 #include <TopTools_IndexedMapOfShape.hxx>
59 #include <TColStd_IndexedDataMapOfTransientTransient.hxx>
65 #include <BRepBuilderAPI_Transform.hxx>
66 #include <BRep_Tool.hxx>
70 #include <TFunction_DriverTable.hxx>
71 #include <TFunction_Driver.hxx>
72 #include <TFunction_Logbook.hxx>
73 #include <TDF_Tool.hxx>
74 #include <TNaming_CopyShape.hxx>
75 #include <Standard_Failure.hxx>
76 #include <Standard_ErrorHandler.hxx> // CAREFUL ! position of this file is critic : see Lucien PIGNOLONI / OCC
78 #define HALF_LENGTH_MAIN_PIPE "Main pipe half length" //"Tuyau principal - demi longueur"
79 #define HALF_LENGTH_INCIDENT_PIPE "Incident pipe half length" //"Tuyau incident - demi longueur"
80 #define CIRCULAR_QUARTER_PIPE "Circular quarter of pipe" //"Circulaire - quart de tuyau"
81 #define THICKNESS "Thickness" //"Epaisseur"
82 #define FLANGE "Flange" // "Collerette"
83 #define CHAMFER_OR_FILLET "Chamfer or fillet" //"Chanfrein ou Raccord"
84 #define JUNCTION_FACE_1 "Junction 1" //"Face de jonction 1"
85 #define JUNCTION_FACE_2 "Junction 2" //"Face de jonction 2"
86 #define JUNCTION_FACE_3 "Junction 3" //"Face de jonction 3"
88 //=============================================================================
92 //=============================================================================
93 GEOMImpl_IAdvancedOperations::GEOMImpl_IAdvancedOperations(GEOM_Engine* theEngine, int theDocID) :
94 GEOM_IOperations(theEngine, theDocID)
96 MESSAGE("GEOMImpl_IAdvancedOperations::GEOMImpl_IAdvancedOperations");
97 myBasicOperations = new GEOMImpl_IBasicOperations(GetEngine(), GetDocID());
98 myBooleanOperations = new GEOMImpl_IBooleanOperations(GetEngine(), GetDocID());
99 myShapesOperations = new GEOMImpl_IShapesOperations(GetEngine(), GetDocID());
100 myTransformOperations = new GEOMImpl_ITransformOperations(GetEngine(), GetDocID());
101 myBlocksOperations = new GEOMImpl_IBlocksOperations(GetEngine(), GetDocID());
102 my3DPrimOperations = new GEOMImpl_I3DPrimOperations(GetEngine(), GetDocID());
103 myLocalOperations = new GEOMImpl_ILocalOperations(GetEngine(), GetDocID());
104 myHealingOperations = new GEOMImpl_IHealingOperations(GetEngine(), GetDocID());
107 //=============================================================================
111 //=============================================================================
112 GEOMImpl_IAdvancedOperations::~GEOMImpl_IAdvancedOperations()
114 MESSAGE("GEOMImpl_IAdvancedOperations::~GEOMImpl_IAdvancedOperations");
115 delete myBasicOperations;
116 delete myBooleanOperations;
117 delete myShapesOperations;
118 delete myTransformOperations;
119 delete myBlocksOperations;
120 delete my3DPrimOperations;
121 delete myLocalOperations;
122 delete myHealingOperations;
125 //=============================================================================
129 //=============================================================================
130 gp_Trsf GEOMImpl_IAdvancedOperations::GetPositionTrsf(double theL1, double theL2,
131 Handle(GEOM_Object) theP1,
132 Handle(GEOM_Object) theP2,
133 Handle(GEOM_Object) theP3)
135 // Old Local Coordinates System oldLCS
137 gp_Pnt P1(-theL1, 0, 0);
138 gp_Pnt P2(theL1, 0, 0);
139 gp_Pnt P3(0, 0, theL2);
141 gp_Dir oldX(gp_Vec(P1, P2));
142 gp_Dir oldZ(gp_Vec(P0, P3));
143 gp_Ax3 oldLCS(P0, oldZ, oldX);
145 // New Local Coordinates System newLCS
146 double LocX, LocY, LocZ;
147 gp_Pnt newP1 = BRep_Tool::Pnt(TopoDS::Vertex(theP1->GetValue()));
148 gp_Pnt newP2 = BRep_Tool::Pnt(TopoDS::Vertex(theP2->GetValue()));
149 gp_Pnt newP3 = BRep_Tool::Pnt(TopoDS::Vertex(theP3->GetValue()));
150 LocX = (newP1.X() + newP2.X()) / 2.;
151 LocY = (newP1.Y() + newP2.Y()) / 2.;
152 LocZ = (newP1.Z() + newP2.Z()) / 2.;
153 gp_Pnt newO(LocX, LocY, LocZ);
155 gp_Dir newX(gp_Vec(newP1, newP2)); // P1P2 Vector
156 gp_Dir newZ(gp_Vec(newO, newP3)); // OP3 Vector
157 gp_Ax3 newLCS = gp_Ax3(newO, newZ, newX);
160 aTrsf.SetDisplacement(oldLCS, newLCS);
165 //=============================================================================
167 * CheckCompatiblePosition
170 //=============================================================================
171 bool GEOMImpl_IAdvancedOperations::CheckCompatiblePosition(double& theL1, double& theL2,
172 Handle(GEOM_Object) theP1,
173 Handle(GEOM_Object) theP2,
174 Handle(GEOM_Object) theP3,
178 gp_Pnt P1 = BRep_Tool::Pnt(TopoDS::Vertex(theP1->GetValue()));
179 gp_Pnt P2 = BRep_Tool::Pnt(TopoDS::Vertex(theP2->GetValue()));
180 gp_Pnt P3 = BRep_Tool::Pnt(TopoDS::Vertex(theP3->GetValue()));
182 double d12 = P1.Distance(P2);
183 double d13 = P1.Distance(P3);
184 double d23 = P2.Distance(P3);
185 // double d2 = newO.Distance(P3);
187 if (Abs(d12) <= Precision::Confusion()) {
188 SetErrorCode("Junctions points P1 and P2 are identical");
191 if (Abs(d13) <= Precision::Confusion()) {
192 SetErrorCode("Junctions points P1 and P3 are identical");
195 if (Abs(d23) <= Precision::Confusion()) {
196 SetErrorCode("Junctions points P2 and P3 are identical");
201 double newL1 = 0.5 * d12;
202 double newL2 = sqrt(pow(d13,2)-pow(newL1,2));
204 // theL1*(1-theTolerance) <= newL1 <= theL1*(1+theTolerance)
206 if (fabs(newL1 - theL1) > Precision::Approximation()) {
207 if ( (newL1 * (1 - theTolerance) -theL1 <= Precision::Approximation()) &&
208 (newL1 * (1 + theTolerance) -theL1 >= Precision::Approximation()) ) {
209 // std::cerr << "theL1 = newL1" << std::endl;
213 SetErrorCode("Dimension for main pipe (L1) is incompatible with new position");
219 // theL2*(1-theTolerance) <= newL2 <= theL2*(1+theTolerance)
221 if (fabs(newL2 - theL2) > Precision::Approximation()) {
222 if ( (newL2 * (1 - theTolerance) -theL2 <= Precision::Approximation()) &&
223 (newL2 * (1 + theTolerance) -theL2 >= Precision::Approximation()) ) {
227 SetErrorCode("Dimension for incident pipe (L2) is incompatible with new position");
237 //=============================================================================
239 * Generate the propagation groups of a Pipe T-Shape used for hexa mesh
241 //=============================================================================
242 bool GEOMImpl_IAdvancedOperations::MakeGroups(Handle(GEOM_Object) theShape, int shapeType,
243 double theR1, double theW1, double theL1,
244 double theR2, double theW2, double theL2,
245 Handle(TColStd_HSequenceOfTransient) theSeq,
250 if (theShape.IsNull()) return false;
252 TopoDS_Shape aShape = theShape->GetValue();
253 if (aShape.IsNull()) {
254 SetErrorCode("Shape is not defined");
258 gp_Trsf aTrsfInv = aTrsf.Inverted();
260 // int expectedGroups = 0;
261 // if (shapeType == TSHAPE_BASIC)
262 // if (Abs(theR2+theW2-theR1-theW1) <= Precision::Approximation())
263 // expectedGroups = 10;
265 // expectedGroups = 11;
266 // else if (shapeType == TSHAPE_CHAMFER || shapeType == TSHAPE_FILLET)
267 // expectedGroups = 12;
269 double aR1Ext = theR1 + theW1;
270 double aR2Ext = theR2 + theW2;
272 /////////////////////////
273 //// Groups of Faces ////
274 /////////////////////////
277 // Comment the following lines when GetInPlace bug is solved
279 // Workaround of GetInPlace bug
280 // Create a bounding box that fits the shape
281 Handle(GEOM_Object) aBox = my3DPrimOperations->MakeBoxDXDYDZ(2*theL1, 2*aR1Ext, aR1Ext+theL2);
282 aBox->GetLastFunction()->SetDescription("");
283 myTransformOperations->TranslateDXDYDZ(aBox, -theL1, -aR1Ext, -aR1Ext);
284 aBox->GetLastFunction()->SetDescription("");
285 // Apply transformation to box
286 BRepBuilderAPI_Transform aTransformationBox(aBox->GetValue(), aTrsf, Standard_False);
287 TopoDS_Shape aBoxShapeTrsf = aTransformationBox.Shape();
288 aBox->GetLastFunction()->SetValue(aBoxShapeTrsf);
290 // Get the shell of the box
291 Handle(GEOM_Object) aShell = Handle(GEOM_Object)::DownCast
292 (myShapesOperations->MakeExplode(aBox, TopAbs_SHELL, true)->Value(1));
293 aBox->GetLastFunction()->SetDescription("");
294 aShell->GetLastFunction()->SetDescription("");
295 // Get the common shapes between shell and shape
296 Handle(GEOM_Object) aCommonCompound = myBooleanOperations->MakeBoolean (theShape, aShell, 1); // MakeCommon
297 if (aCommonCompound.IsNull()) {
298 SetErrorCode(myBooleanOperations->GetErrorCode());
301 aCommonCompound->GetLastFunction()->SetDescription("");
302 // Explode the faces of common shapes => 3 faces
303 Handle(TColStd_HSequenceOfTransient) aCommonFaces =
304 myShapesOperations->MakeExplode(aCommonCompound, TopAbs_FACE, true);
305 aCommonCompound->GetLastFunction()->SetDescription("");
306 std::list<Handle(GEOM_Object)> aCompoundOfFacesList;
308 for (int i=0 ; i<= aCommonFaces->Length()-4 ; i+=4) {
309 std::list<Handle(GEOM_Object)> aFacesList;
310 for (int j = 1 ; j <= 4 ; j++) {
311 Handle(GEOM_Object) aFace = Handle(GEOM_Object)::DownCast(aCommonFaces->Value(i+j)); // Junction faces
312 if (!aFace.IsNull()) {
313 aFace->GetLastFunction()->SetDescription("");
314 aFacesList.push_back(aFace);
317 Handle(GEOM_Object) aCompoundOfFaces = myShapesOperations->MakeCompound(aFacesList);
318 if (!aCompoundOfFaces.IsNull()) {
319 aCompoundOfFaces->GetLastFunction()->SetDescription("");
320 aCompoundOfFacesList.push_back(aCompoundOfFaces);
324 if (aCompoundOfFacesList.size() == 3) {
325 Handle(GEOM_Object) aPln1 = aCompoundOfFacesList.front();
326 aCompoundOfFacesList.pop_front();
327 Handle(GEOM_Object) aPln2 = aCompoundOfFacesList.front();
328 aCompoundOfFacesList.pop_front();
329 Handle(GEOM_Object) aPln3 = aCompoundOfFacesList.front();
330 aCompoundOfFacesList.pop_front();
335 // Uncomment the following lines when GetInPlace bug is solved
337 // Handle(GEOM_Object) aP1 = myBasicOperations->MakePointXYZ(-theL1, 0, 0);
338 // Handle(GEOM_Object) aP2 = myBasicOperations->MakePointXYZ(-0, 0, theL2);
339 // Handle(GEOM_Object) aP3 = myBasicOperations->MakePointXYZ(theL1, 0, 0);
340 // aP1->GetLastFunction()->SetDescription("");
341 // aP2->GetLastFunction()->SetDescription("");
342 // aP3->GetLastFunction()->SetDescription("");
343 // Handle(GEOM_Object) aV1 = myBasicOperations->MakeVectorDXDYDZ(-1, 0, 0);
344 // Handle(GEOM_Object) aV2 = myBasicOperations->MakeVectorDXDYDZ(0, 0, 1);
345 // Handle(GEOM_Object) aV3 = myBasicOperations->MakeVectorDXDYDZ(1, 0, 0);
346 // aV1->GetLastFunction()->SetDescription("");
347 // aV2->GetLastFunction()->SetDescription("");
348 // aV3->GetLastFunction()->SetDescription("");
349 // Handle(GEOM_Object) aPln1 = myBasicOperations->MakePlanePntVec(aP1, aV1, 2*(aR1Ext+theL2));
350 // Handle(GEOM_Object) aPln2 = myBasicOperations->MakePlanePntVec(aP2, aV2, 2*(aR2Ext));
351 // Handle(GEOM_Object) aPln3 = myBasicOperations->MakePlanePntVec(aP3, aV3, 2*(aR1Ext+theL2));
352 // aPln1->GetLastFunction()->SetDescription("");
353 // aPln2->GetLastFunction()->SetDescription("");
354 // aPln3->GetLastFunction()->SetDescription("");
356 // BRepBuilderAPI_Transform aTransformation1(aPln1->GetValue(), aTrsf, Standard_False);
357 // TopoDS_Shape aTrsf_Shape1 = aTransformation1.Shape();
358 // aPln1->GetLastFunction()->SetValue(aTrsf_Shape1);
359 // BRepBuilderAPI_Transform aTransformation2(aPln2->GetValue(), aTrsf, Standard_False);
360 // TopoDS_Shape aTrsf_Shape2 = aTransformation2.Shape();
361 // aPln2->GetLastFunction()->SetValue(aTrsf_Shape2);
362 // BRepBuilderAPI_Transform aTransformation3(aPln3->GetValue(), aTrsf, Standard_False);
363 // TopoDS_Shape aTrsf_Shape3 = aTransformation3.Shape();
364 // aPln3->GetLastFunction()->SetValue(aTrsf_Shape3);
368 Handle(GEOM_Object) junctionFaces1 = myShapesOperations->GetInPlace(theShape, aPln1);
369 if (junctionFaces1.IsNull())
370 junctionFaces1 = myShapesOperations->GetShapesOnShapeAsCompound
371 (aPln1, theShape, TopAbs_FACE, GEOMAlgo_ST_ONIN);
372 if (!junctionFaces1.IsNull()) {
373 junctionFaces1->GetLastFunction()->SetDescription("");
374 junctionFaces1->SetName("JUNCTION_FACE_1");
375 theSeq->Append(junctionFaces1);
378 SetErrorCode("Junction face 1 not found");
379 // theSeq->Append(aPln1);
382 Handle(GEOM_Object) junctionFaces2 = myShapesOperations->GetInPlace(theShape, aPln2);
383 if (junctionFaces2.IsNull())
384 junctionFaces2 = myShapesOperations->GetShapesOnShapeAsCompound
385 (aPln2, theShape, TopAbs_FACE, GEOMAlgo_ST_ONIN);
386 if (!junctionFaces2.IsNull()) {
387 junctionFaces2->GetLastFunction()->SetDescription("");
388 junctionFaces2->SetName("JUNCTION_FACE_2");
389 theSeq->Append(junctionFaces2);
392 SetErrorCode("Junction face 2 not found");
393 // theSeq->Append(aPln2);
396 Handle(GEOM_Object) junctionFaces3 = myShapesOperations->GetInPlace(theShape, aPln3);
397 if (junctionFaces3.IsNull())
398 junctionFaces3 = myShapesOperations->GetShapesOnShapeAsCompound
399 (aPln3, theShape, TopAbs_FACE, GEOMAlgo_ST_ONIN);
400 if (!junctionFaces3.IsNull()) {
401 junctionFaces3->GetLastFunction()->SetDescription("");
402 junctionFaces3->SetName("JUNCTION_FACE_3");
403 theSeq->Append(junctionFaces3);
406 SetErrorCode("Junction face 3 not found");
407 // theSeq->Append(aPln3);
410 // Comment the following lines when GetInPlace bug is solved
414 /////////////////////////
415 //// Groups of Edges ////
416 /////////////////////////
417 // Result of propagate
419 Handle(GEOM_Function) aFunction = theShape->GetLastFunction();
421 TCollection_AsciiString theDesc = aFunction->GetDescription();
422 Handle(TColStd_HSequenceOfTransient) aSeqPropagate = myBlocksOperations->Propagate(theShape);
423 if (aSeqPropagate.IsNull() || aSeqPropagate->Length() == 0) {
424 SetErrorCode("Propagation groups not found");
427 Standard_Integer nbEdges, aNbGroups = aSeqPropagate->Length();
428 // Recover previous description to get rid of Propagate dump
429 aFunction->SetDescription(theDesc);
432 bool circularFoundAndAdded = false;
433 bool circularFound10 = false;
434 bool incidentPipeFound = false;
435 bool mainPipeFound = false;
436 bool mainPipeFoundAndAdded = false;
437 bool radialFound =false;
438 bool flangeFound = false;
439 bool flangeFoundAndAdded = false;
440 bool chamferOrFilletFound = false;
442 for (int i=1 ; i<= aNbGroups; i++) {
445 Handle(GEOM_Object) aGroup = Handle(GEOM_Object)::DownCast(aSeqPropagate->Value(i));
449 TopoDS_Shape aGroupShape = aGroup->GetValue();
450 BRepBuilderAPI_Transform aTransformationShapeInv(aGroupShape, aTrsfInv, Standard_False);
451 TopoDS_Shape aGroupShapeTrsfInv = aTransformationShapeInv.Shape();
453 TopTools_IndexedMapOfShape anEdgesMap;
454 TopExp::MapShapes(aGroupShapeTrsfInv,TopAbs_EDGE, anEdgesMap);
455 nbEdges = anEdgesMap.Extent();
457 if (shapeType == TSHAPE_BASIC) {
458 if ((nbEdges == 21) || /*R1Ext = R2Ext*/(nbEdges == 17)){
460 aGroup->SetName("THICKNESS");
462 else if (nbEdges == 6) {
463 if (!circularFoundAndAdded) {
464 circularFoundAndAdded = true;
466 aGroup->SetName("CIRCULAR_QUARTER_PIPE");
469 else if (nbEdges == 8) {
470 incidentPipeFound = true;
471 mainPipeFound = false;
475 TopExp_Explorer Ex(aGroupShapeTrsfInv,TopAbs_VERTEX);
477 gp_Pnt aP = BRep_Tool::Pnt(TopoDS::Vertex(Ex.Current()));
478 double x=aP.X(), y=aP.Y(), z=aP.Z();
481 if ((Abs(x) > aR2Ext + Precision::Confusion()) ||
482 (Abs(y) > aR2Ext + Precision::Confusion())) {
483 incidentPipeFound = false;
486 if ( z < -Precision::Confusion()) {
487 // length of main pipe
488 mainPipeFound = true;
489 if (!mainPipeFoundAndAdded) {
490 mainPipeFoundAndAdded = true;
492 aGroup->SetName("HALF_LENGTH_MAIN_PIPE");
496 else if (Abs(x) > (theL1-Precision::Confusion())) {
497 // discretisation circulaire
499 if (!circularFoundAndAdded) {
500 circularFoundAndAdded = true;
502 aGroup->SetName("CIRCULAR_QUARTER_PIPE");
507 if (incidentPipeFound) {
509 aGroup->SetName("HALF_LENGTH_INCIDENT_PIPE");
511 if (!addGroup && (!incidentPipeFound &&
515 // Flange (collerette)
518 aGroup->SetName("FLANGE");
524 else if (shapeType == TSHAPE_CHAMFER || shapeType == TSHAPE_FILLET) {
527 aGroup->SetName("THICKNESS");
529 else if ((nbEdges == 10) || (nbEdges == 6)) {
530 if (!circularFoundAndAdded) {
532 circularFoundAndAdded = true;
533 aGroup->SetName("CIRCULAR_QUARTER_PIPE");
535 circularFound10 = true;
538 else if (!circularFound10 && nbEdges == 10) {
539 circularFound10 = true;
541 aGroup->SetName("CIRCULAR_QUARTER_PIPE");
544 else if (nbEdges == 8) {
545 incidentPipeFound = true;
546 mainPipeFound = true;
549 bool isNearZ0 = false;
550 bool isBelowZ0 = false;
552 TopExp_Explorer Ex (aGroupShapeTrsfInv,TopAbs_VERTEX);
554 gp_Pnt aP = BRep_Tool::Pnt(TopoDS::Vertex(Ex.Current()));
555 double x=aP.X(), y=aP.Y(), z=aP.Z();
557 // tuy_princ_long_avant & tuy_princ_long_apres
558 //bool isMain = (((z < Precision::Confusion()) || (x < Precision::Confusion())) &&
559 // ((y <= aR1Ext + Precision::Confusion()) ||
560 // (y <= -(aR1Ext + Precision::Confusion())) ||
561 // (y <= theR1 + Precision::Confusion()) ||
562 // (y == -(theR1 + Precision::Confusion()))));
563 bool isMain = ((z < Precision::Confusion() || x < Precision::Confusion()) &&
564 (fabs(y) > theR1 - Precision::Confusion() ||
565 fabs(y) < Precision::Confusion()));
568 mainPipeFound = false;
572 //if (z < Precision::Confusion() && !isMain) {
573 // flangeFound = true;
574 // if (!flangeFoundAndAdded) {
575 // flangeFoundAndAdded = true;
577 // aGroup->SetName("FLANGE");
580 if (fabs(z) < Precision::Confusion()) isNearZ0 = true;
581 if (z < - Precision::Confusion()) isBelowZ0 = true;
584 if ((Abs(x) > aR2Ext + Precision::Confusion()) ||
585 (Abs(y) > aR2Ext + Precision::Confusion())) {
586 incidentPipeFound = false;
592 aGroup->SetName("HALF_LENGTH_MAIN_PIPE");
594 if (incidentPipeFound) {
596 aGroup->SetName("HALF_LENGTH_INCIDENT_PIPE");
598 if (isNearZ0 && !isBelowZ0) {
600 if (!flangeFoundAndAdded) {
601 flangeFoundAndAdded = true;
603 aGroup->SetName("FLANGE");
606 if (!addGroup && (!incidentPipeFound &&
609 !chamferOrFilletFound)) {
611 chamferOrFilletFound = true;
612 if (shapeType == TSHAPE_CHAMFER)
613 aGroup->SetName("CHAMFER");
615 aGroup->SetName("FILLET");
621 // Add group to the list
623 theSeq->Append(aGroup);
630 bool GEOMImpl_IAdvancedOperations::MakePipeTShapePartition(Handle(GEOM_Object) theShape,
631 double theR1, double theW1, double theL1,
632 double theR2, double theW2, double theL2,
633 double theH, double theW,
634 double theRF, bool isNormal)
638 // Build tools for partition operation:
639 // 1 face and 2 planes
641 Handle(GEOM_Object) arete_intersect_int;
642 Handle(GEOM_Object) wire_t, wire_t2, face_t, face_t2;
643 Handle(GEOM_Object) chan_racc;
644 Handle(GEOM_Object) vi1, vi2;
645 Handle(GEOM_Object) Te3;
648 #if OCC_VERSION_LARGE > 0x06010000
651 Handle(GEOM_Object) Vector_Z = myBasicOperations->MakeVectorDXDYDZ(0, 0, 1);
652 Vector_Z->GetLastFunction()->SetDescription("");
655 double aSize = 2*(theL1 + theL2);
656 double aR1Ext = theR1 + theW1;
657 double aR2Ext = theR2 + theW2;
658 double theVertCylinderRadius = aR2Ext + theW + theRF;
659 double theHoriCylinderRadius = aR1Ext + theH + theRF;
661 // Common edges on internal cylinder
662 Handle(GEOM_Object) box_i = my3DPrimOperations->MakeBoxDXDYDZ(theR2, theR2, theR1);
663 box_i->GetLastFunction()->SetDescription("");
664 box_i = myTransformOperations->TranslateDXDYDZ(box_i, -theR2, -theR2, 0);
665 box_i->GetLastFunction()->SetDescription("");
667 Handle(GEOM_Function) aFunction = theShape->GetLastFunction();
668 TCollection_AsciiString theDesc = aFunction->GetDescription();
669 Handle(TColStd_HSequenceOfTransient) edges_i =
670 myShapesOperations->GetShapesOnBox(box_i, theShape, TopAbs_EDGE, GEOMAlgo_ST_IN);
671 // Recover previous description to get rid of Propagate dump
672 aFunction->SetDescription(theDesc);
673 if (edges_i.IsNull() || edges_i->Length() == 0) {
674 SetErrorCode("Internal edges not found");
677 for (int i=1; i<=edges_i->Length();i++) {
678 Handle(GEOM_Object) anObj = Handle(GEOM_Object)::DownCast(edges_i->Value(i));
679 anObj->GetLastFunction()->SetDescription("");
681 arete_intersect_int = Handle(GEOM_Object)::DownCast(edges_i->Value(1));
683 // search for vertices located on both internal pipes
684 aFunction = theShape->GetLastFunction();
685 theDesc = aFunction->GetDescription();
686 Handle(TColStd_HSequenceOfTransient) vertices_i =
687 myShapesOperations->GetShapesOnBox(box_i, theShape, TopAbs_VERTEX, GEOMAlgo_ST_ONIN);
688 // Recover previous description to get rid of Propagate dump
689 aFunction->SetDescription(theDesc);
690 if (vertices_i.IsNull() || vertices_i->Length() == 0) {
691 SetErrorCode("Internal vertices not found");
695 for (int i = 1; i <= vertices_i->Length(); i++) {
696 Handle(GEOM_Object) v = Handle(GEOM_Object)::DownCast(vertices_i->Value(i));
697 v->GetLastFunction()->SetDescription("");
698 TopoDS_Vertex aVertex = TopoDS::Vertex(v->GetValue());
699 gp_Pnt aP = BRep_Tool::Pnt(aVertex);
700 // std::cout << "Coords: " << aP.X() << ", " << aP.Y() << ", " << aP.Z() << std::endl;
701 if (Abs(aP.X()) <= Precision::Confusion()) {
702 if (Abs(aP.Y()) - theR1 <= Precision::Confusion()) {
705 } else if (Abs(aP.Y()) <= Precision::Confusion()) {
706 if (Abs(aP.X()) - theR1 <= Precision::Confusion()) {
712 std::list<Handle(GEOM_Object)> theShapes;
715 Handle(GEOM_Object) ve1, ve2;
717 Handle(GEOM_Object) box_e = my3DPrimOperations->MakeBoxDXDYDZ(aR2Ext, aR2Ext, aR1Ext);
718 box_e->GetLastFunction()->SetDescription("");
719 box_e = myTransformOperations->TranslateDXDYDZ(box_e, -aR2Ext, -aR2Ext, 0);
720 box_e->GetLastFunction()->SetDescription("");
721 // Common edges on external cylinder
722 aFunction = theShape->GetLastFunction();
723 theDesc = aFunction->GetDescription();
724 Handle(TColStd_HSequenceOfTransient) edges_e =
725 myShapesOperations->GetShapesOnBox(box_e, theShape, TopAbs_EDGE, GEOMAlgo_ST_IN);
726 // Recover previous description to get rid of Propagate dump
727 aFunction->SetDescription(theDesc);
728 if (edges_e.IsNull() || edges_e->Length() == 0) {
729 SetErrorCode("External edges not found");
732 for (int i=1; i<=edges_e->Length();i++) {
733 Handle(GEOM_Object) anObj = Handle(GEOM_Object)::DownCast(edges_e->Value(i));
734 anObj->GetLastFunction()->SetDescription("");
737 // search for vertices located on both external pipes
738 aFunction = theShape->GetLastFunction();
739 theDesc = aFunction->GetDescription();
740 Handle(TColStd_HSequenceOfTransient) vertices_e =
741 myShapesOperations->GetShapesOnBox(box_e, theShape, TopAbs_VERTEX, GEOMAlgo_ST_ONIN);
742 // Recover previous description to get rid of Propagate dump
743 aFunction->SetDescription(theDesc);
744 if (vertices_e.IsNull() || vertices_e->Length() == 0) {
745 SetErrorCode("External vertices not found");
749 for (int i = 1; i <= vertices_e->Length(); i++) {
750 Handle(GEOM_Object) v = Handle(GEOM_Object)::DownCast(vertices_e->Value(i));
751 v->GetLastFunction()->SetDescription("");
752 TopoDS_Vertex aVertex = TopoDS::Vertex(v->GetValue());
753 gp_Pnt aP = BRep_Tool::Pnt(aVertex);
754 // std::cout << "Coords: " << aP.X() << ", " << aP.Y() << ", " << aP.Z() << std::endl;
755 if (Abs(aP.X()) <= Precision::Confusion()) {
756 if (Abs(aP.Y()) - theR2 > Precision::Confusion()) {
759 } else if (Abs(aP.Y()) <= Precision::Confusion()) {
760 if (Abs(aP.X()) - theR2 > Precision::Confusion()) {
764 if ( !ve1.IsNull() && !ve2.IsNull())
767 Handle(GEOM_Object) edge_e1, edge_e2;
769 edge_e1 = myBasicOperations->MakeLineTwoPnt(ve1, vi1);
770 if (edge_e1.IsNull()) {
771 SetErrorCode("Edge 1 could not be built");
775 edge_e2 = myBasicOperations->MakeLineTwoPnt(ve2, vi2);
776 if (edge_e2.IsNull()) {
777 SetErrorCode("Edge 2 could not be built");
781 edge_e1->GetLastFunction()->SetDescription("");
782 edge_e2->GetLastFunction()->SetDescription("");
784 std::list<Handle(GEOM_Object)> edge_e_elist;
785 edge_e_elist.push_back(arete_intersect_int);
786 edge_e_elist.push_back(edge_e1);
787 edge_e_elist.push_back(Handle(GEOM_Object)::DownCast(edges_e->Value(1)));
788 edge_e_elist.push_back(edge_e2);
789 wire_t = myShapesOperations->MakeWire(edge_e_elist, 1e-7);
790 if (wire_t.IsNull()) {
791 SetErrorCode("Impossible to build wire");
794 wire_t->GetLastFunction()->SetDescription("");
795 face_t = myShapesOperations->MakeFace(wire_t, false);
796 if (face_t.IsNull()) {
797 SetErrorCode("Impossible to build face");
800 face_t->GetLastFunction()->SetDescription("");
802 theShapes.push_back(theShape);
803 theShapes.push_back(vi1);
804 theShapes.push_back(vi2);
805 theShapes.push_back(ve1);
806 theShapes.push_back(ve2);
807 theShapes.push_back(edge_e1);
808 theShapes.push_back(edge_e2);
809 theShapes.push_back(wire_t);
810 theShapes.push_back(face_t);
813 Handle(GEOM_Object) P1, P2, P3, P4, P5, P6;
814 int idP1, idP2, idP3, idP4;
819 Handle(GEOM_Object) box_e = my3DPrimOperations->MakeBoxDXDYDZ
820 (theVertCylinderRadius, theVertCylinderRadius, theHoriCylinderRadius);
821 box_e->GetLastFunction()->SetDescription("");
822 box_e = myTransformOperations->TranslateDXDYDZ
823 (box_e, -theVertCylinderRadius, -theVertCylinderRadius, 0);
824 box_e->GetLastFunction()->SetDescription("");
826 aFunction = theShape->GetLastFunction();
827 theDesc = aFunction->GetDescription();
828 Handle(TColStd_HSequenceOfTransient) extremVertices =
829 myShapesOperations->GetShapesOnBox(box_e, theShape, TopAbs_VERTEX, GEOMAlgo_ST_ONIN);
830 // Recover previous description to get rid of Propagate dump
831 aFunction->SetDescription(theDesc);
833 if (extremVertices.IsNull() || extremVertices->Length() == 0) {
835 SetErrorCode("Vertices on chamfer not found");
837 SetErrorCode("Vertices on fillet not found");
841 theShapes.push_back(theShape);
842 theShapes.push_back(box_e);
843 if (extremVertices->Length() != 6) {
844 // for (int i=1; i<=extremVertices->Length(); i++){
845 // theShapes.push_back(Handle(GEOM_Object)::DownCast(extremVertices->Value(i)));
847 // Handle(GEOM_Object) aCompound = myShapesOperations->MakeCompound(theShapes);
848 // TopoDS_Shape aCompoundShape = aCompound->GetValue();
849 // theShape->GetLastFunction()->SetValue(aCompoundShape);
850 SetErrorCode("Bad number of vertices on chamfer found");
854 for (int i=1; i<=extremVertices->Length(); i++){
855 Handle(GEOM_Object) aV = Handle(GEOM_Object)::DownCast(extremVertices->Value(i));
856 aV->GetLastFunction()->SetDescription("");
857 gp_Pnt aP = BRep_Tool::Pnt(TopoDS::Vertex(aV->GetValue()));
859 if (Abs(aP.X()) <= Precision::Confusion()) {
860 if (Abs(aP.Y()) - theR2 > Precision::Confusion()) {
862 if (aP.Z()-ZX > Precision::Confusion()) {
869 if (Abs(aP.X()) - theR2 > Precision::Confusion()) {
871 if (aP.Z() - ZY > Precision::Confusion()) {
888 P1 = Handle(GEOM_Object)::DownCast(extremVertices->Value(idP1));
889 P2 = Handle(GEOM_Object)::DownCast(extremVertices->Value(idP2));
890 P3 = Handle(GEOM_Object)::DownCast(extremVertices->Value(idP3));
891 P4 = Handle(GEOM_Object)::DownCast(extremVertices->Value(idP4));
893 Handle(GEOM_Object) Cote_1 = myBasicOperations->MakeLineTwoPnt(P1, vi1);
894 if (Cote_1.IsNull()) {
895 SetErrorCode("Impossible to build edge in thickness");
898 Cote_1->GetLastFunction()->SetDescription("");
900 Handle(GEOM_Object) Cote_2 = myBasicOperations->MakeLineTwoPnt(vi2, P3);
901 if (Cote_2.IsNull()) {
902 SetErrorCode("Impossible to build edge in thickness");
905 Cote_2->GetLastFunction()->SetDescription("");
907 // edge_chan_princ = arete du chanfrein (ou raccord) sur le tuyau principal
908 // edge_chan_inc = arete du chanfrein (ou raccord) sur le tuyau incident
909 // std::cerr << "Getting chamfer edge on main pipe" << std::endl;
910 Handle(GEOM_Object) edge_chan_princ = myBlocksOperations->GetEdge(theShape, P1, P3);
911 if (edge_chan_princ.IsNull()) {
912 SetErrorCode("Impossible to find edge on main pipe");
915 edge_chan_princ->GetLastFunction()->SetDescription("");
917 Handle(GEOM_Object) edge_chan_inc = myBlocksOperations->GetEdge(theShape, P2, P4);
918 if (edge_chan_inc.IsNull()) {
919 SetErrorCode("Impossible to find edge on incident pipe");
922 edge_chan_inc->GetLastFunction()->SetDescription("");
924 std::list<Handle(GEOM_Object)> edgeList1;
925 edgeList1.push_back(edge_chan_princ);
926 edgeList1.push_back(Cote_1);
927 edgeList1.push_back(arete_intersect_int);
928 edgeList1.push_back(Cote_2);
930 // std::cerr << "Creating wire 1" << std::endl;
931 wire_t = myShapesOperations->MakeWire(edgeList1, 1e-7);
932 if (wire_t.IsNull()) {
933 SetErrorCode("Impossible to build wire");
936 wire_t->GetLastFunction()->SetDescription("");
938 // std::cerr << "Creating face 1" << std::endl;
939 face_t = myShapesOperations->MakeFace(wire_t, false);
940 if (face_t.IsNull()) {
941 SetErrorCode("Impossible to build face");
944 face_t->GetLastFunction()->SetDescription("");
945 theShapes.push_back(face_t);
947 gp_Pnt aP2 = BRep_Tool::Pnt(TopoDS::Vertex(P2->GetValue()));
948 gp_Pnt aP5 = BRep_Tool::Pnt(TopoDS::Vertex(vi1->GetValue()));
949 double deltaZ = aP2.Z() - aP5.Z();
950 // std::cerr << "Creating new point from vi1 with deltaZ = " << deltaZ << std::endl;
951 Handle(GEOM_Object) P5bis = myTransformOperations->TranslateDXDYDZCopy(vi1, 0, 0, deltaZ);
952 if (P5bis.IsNull()) {
953 SetErrorCode("Impossible to translate vertex");
956 P5bis->GetLastFunction()->SetDescription("");
958 gp_Pnt aP4 = BRep_Tool::Pnt(TopoDS::Vertex(P4->GetValue()));
959 gp_Pnt aP6 = BRep_Tool::Pnt(TopoDS::Vertex(vi2->GetValue()));
960 deltaZ = aP4.Z() - aP6.Z();
961 // std::cerr << "Creating new point from vi2 with deltaZ = " << deltaZ << std::endl;
962 Handle(GEOM_Object) P6bis = myTransformOperations->TranslateDXDYDZCopy(vi2, 0, 0, deltaZ);
963 if (P6bis.IsNull()) {
964 SetErrorCode("Impossible to translate vertex");
967 P6bis->GetLastFunction()->SetDescription("");
969 // std::cerr << "Creating new line 1 from 2 previous points" << std::endl;
970 Handle(GEOM_Object) Cote_3 = myBasicOperations->MakeLineTwoPnt(P5bis, P2);
971 if (Cote_3.IsNull()) {
972 SetErrorCode("Impossible to build edge in thickness");
975 Cote_3->GetLastFunction()->SetDescription("");
977 // std::cerr << "Creating new line 2 from 2 previous points" << std::endl;
978 Handle(GEOM_Object) Cote_4 = myBasicOperations->MakeLineTwoPnt(P6bis, P4);
979 if (Cote_4.IsNull()) {
980 SetErrorCode("Impossible to build edge in thickness");
983 Cote_4->GetLastFunction()->SetDescription("");
985 // std::cerr << "Creating new line 3 from 2 previous points" << std::endl;
986 Handle(GEOM_Object) Cote_5 = myBasicOperations->MakeLineTwoPnt(P5bis, P6bis);
987 if (Cote_4.IsNull()) {
988 SetErrorCode("Impossible to build edge in thickness");
991 Cote_5->GetLastFunction()->SetDescription("");
993 //std::list<Handle(GEOM_Object)> edgeList2;
994 //edgeList2.push_back(edge_chan_inc);
995 //edgeList2.push_back(Cote_3);
996 //edgeList2.push_back(Cote_5);
997 //edgeList2.push_back(Cote_4);
998 // std::cerr << "Creating wire 2" << std::endl;
999 //wire_t2 = myShapesOperations->MakeWire(edgeList2, 1e-7);
1000 //if (wire_t2.IsNull()) {
1001 // SetErrorCode("Impossible to build wire");
1004 //wire_t2->GetLastFunction()->SetDescription("");
1005 // std::cerr << "Creating face 2" << std::endl;
1006 //face_t2 = myShapesOperations->MakeFace(wire_t2, false);
1008 // Mantis issue 0021682
1009 face_t2 = my3DPrimOperations->MakePrismVecH(edge_chan_inc, Cote_4, - (theR2 + theW2));
1010 //face_t2 = my3DPrimOperations->MakePrismVecH(edge_chan_inc, Cote_4, - 2.0*theR2);
1011 if (face_t2.IsNull()) {
1012 SetErrorCode("Impossible to build face");
1015 face_t2->GetLastFunction()->SetDescription("");
1016 theShapes.push_back(face_t2);
1020 Handle(GEOM_Object) aP0 = myBasicOperations->MakePointXYZ(0, 0, 0);
1021 Handle(GEOM_Object) aVZ = myBasicOperations->MakeVectorDXDYDZ(0, 0, 1);
1022 Handle(GEOM_Object) aVXZ = myBasicOperations->MakeVectorDXDYDZ(aR1Ext, 0, 0.5*(theL1+theVertCylinderRadius));
1023 Handle(GEOM_Object) aPlnOZ = myBasicOperations->MakePlanePntVec(aP0, aVZ, aSize);
1024 Handle(GEOM_Object) aPlnOXZ = myBasicOperations->MakePlanePntVec(aP0, aVXZ, aSize);
1025 aP0->GetLastFunction()->SetDescription("");
1026 aVZ->GetLastFunction()->SetDescription("");
1027 aVXZ->GetLastFunction()->SetDescription("");
1028 aPlnOZ->GetLastFunction()->SetDescription("");
1029 aPlnOXZ->GetLastFunction()->SetDescription("");
1030 theShapes.push_back(aPlnOZ);
1031 theShapes.push_back(aPlnOXZ);
1034 Handle(TColStd_HSequenceOfTransient) partitionShapes = new TColStd_HSequenceOfTransient;
1035 Handle(TColStd_HSequenceOfTransient) theTools = new TColStd_HSequenceOfTransient;
1036 Handle(TColStd_HSequenceOfTransient) theKeepInside = new TColStd_HSequenceOfTransient;
1037 Handle(TColStd_HSequenceOfTransient) theRemoveInside = new TColStd_HSequenceOfTransient;
1038 Handle(TColStd_HArray1OfInteger) theMaterials;
1040 partitionShapes->Append(theShape);
1041 theTools->Append(aPlnOZ);
1042 if (Abs(aR1Ext - aR2Ext) > Precision::Confusion())
1043 theTools->Append(aPlnOXZ);
1044 theTools->Append(face_t);
1046 theTools->Append(face_t2);
1048 Te3 = myBooleanOperations->MakePartition
1049 (partitionShapes, theTools, theKeepInside, theRemoveInside,
1050 TopAbs_SOLID, false, theMaterials, 0, false);
1052 SetErrorCode("Impossible to build partition of TShape");
1055 Te3->GetLastFunction()->SetDescription("");
1057 // Last verification: result should be a block
1058 std::list<GEOMImpl_IBlocksOperations::BCError> errList;
1059 if (!myBlocksOperations->CheckCompoundOfBlocks(Te3,errList)) {
1060 SetErrorCode("TShape is not a compound of block");
1064 // // BEGIN Compound of created shapes - Only for debug purpose
1065 // theShapes.clear();
1066 // theShapes.push_back(theShape);
1067 // theShapes.push_back(aPlnOZ);
1068 // if (Abs(aR1Ext - aR2Ext) > Precision::Confusion() )
1069 // theShapes.push_back(aPlnOXZ);
1070 // theShapes.push_back(face_t);
1072 // theShapes.push_back(face_t2);
1074 // Handle(GEOM_Object) aCompound = myShapesOperations->MakeCompound(theShapes);
1075 // TopoDS_Shape aCompoundShape = aCompound->GetValue();
1076 // theShape->GetLastFunction()->SetValue(aCompoundShape);
1077 // // END Compound of created shapes - Only for debug purpose
1079 TopoDS_Shape aShape = Te3->GetValue();
1080 theShape->GetLastFunction()->SetValue(aShape);
1081 } catch (Standard_Failure) {
1082 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1083 SetErrorCode(aFail->GetMessageString());
1091 // Mirror and glue faces
1092 bool GEOMImpl_IAdvancedOperations::MakePipeTShapeMirrorAndGlue(Handle(GEOM_Object) theShape,
1093 double theR1, double theW1, double theL1,
1094 double theR2, double theW2, double theL2)
1099 double aSize = 2*(theL1 + theL2);
1100 double aR1Ext = theR1 + theW1;
1103 Handle(GEOM_Object) aP0 = myBasicOperations->MakePointXYZ(0, 0, 0);
1104 aP0->GetLastFunction()->SetDescription("");
1105 Handle(GEOM_Object) aVX = myBasicOperations->MakeVectorDXDYDZ(1, 0, 0);
1106 Handle(GEOM_Object) aVY = myBasicOperations->MakeVectorDXDYDZ(0, 1, 0);
1107 aVX->GetLastFunction()->SetDescription("");
1108 aVY->GetLastFunction()->SetDescription("");
1109 Handle(GEOM_Object) aPlane_OX = myBasicOperations->MakePlanePntVec(aP0, aVX, 2*(aR1Ext + theL2));
1110 Handle(GEOM_Object) aPlane_OY = myBasicOperations->MakePlanePntVec(aP0, aVY, aSize);
1111 aPlane_OX->GetLastFunction()->SetDescription("");
1112 aPlane_OY->GetLastFunction()->SetDescription("");
1114 Handle(GEOM_Object) Te4 = myTransformOperations->MirrorPlaneCopy(theShape, aPlane_OX);
1116 SetErrorCode("Impossible to build mirror of quarter TShape");
1120 Handle(GEOM_Object) Te5 = myTransformOperations->MirrorPlaneCopy(theShape, aPlane_OY);
1122 SetErrorCode("Impossible to build mirror of half TShape");
1126 Handle(GEOM_Object) Te6 = myTransformOperations->MirrorPlaneCopy(Te4, aPlane_OY);
1128 SetErrorCode("Impossible to build mirror of half TShape");
1132 std::list<Handle(GEOM_Object)> aShapesList;
1133 aShapesList.push_back(theShape);
1134 aShapesList.push_back(Te4);
1135 aShapesList.push_back(Te5);
1136 aShapesList.push_back(Te6);
1137 Handle(GEOM_Object) Te7 = myShapesOperations->MakeCompound(aShapesList);
1139 SetErrorCode("Impossible to build compound");
1143 // Copy source shape
1144 TopoDS_Shape aShapeCopy;
1145 TColStd_IndexedDataMapOfTransientTransient aMapTShapes;
1146 TNaming_CopyShape::CopyTool(Te7->GetValue(), aMapTShapes, aShapeCopy);
1148 Handle(GEOM_Object) Te8 = myShapesOperations->MakeGlueFaces(Te7, 1e-7, true);
1150 SetErrorCode("Impossible to glue faces of TShape");
1154 TopoDS_Shape aShape = Te8->GetValue();
1155 BRepCheck_Analyzer anAna (aShape, Standard_True);
1157 if (!anAna.IsValid()) {
1158 // Try to do gluing with the tolerance equal to maximal
1159 // tolerance of vertices of the source shape.
1160 Standard_Real aTolMax = -RealLast();
1162 for (TopExp_Explorer ExV (aShapeCopy, TopAbs_VERTEX); ExV.More(); ExV.Next()) {
1163 TopoDS_Vertex aVertex = TopoDS::Vertex(ExV.Current());
1164 Standard_Real aTol = BRep_Tool::Tolerance(aVertex);
1166 if (aTol > aTolMax) {
1172 Te7->GetLastFunction()->SetValue(aShapeCopy);
1173 Te8 = myShapesOperations->MakeGlueFaces(Te7, aTolMax, true);
1176 SetErrorCode("Impossible to glue faces of TShape");
1180 aShape = Te8->GetValue();
1184 theShape->GetLastFunction()->SetValue(aShape);
1186 Te4->GetLastFunction()->SetDescription("");
1187 Te5->GetLastFunction()->SetDescription("");
1188 Te6->GetLastFunction()->SetDescription("");
1189 Te7->GetLastFunction()->SetDescription("");
1190 Te8->GetLastFunction()->SetDescription("");
1196 //=============================================================================
1199 * \brief Create a T-shape object with specified caracteristics for the main and
1200 * the incident pipes (radius, width, half-length).
1201 * Center of the shape is (0,0,0). The main plane of the T-shape is XOY.
1202 * \param theR1 Internal radius of main pipe
1203 * \param theW1 Width of main pipe
1204 * \param theL1 Half-length of main pipe
1205 * \param theR2 Internal radius of incident pipe (R2 < R1)
1206 * \param theW2 Width of incident pipe (R2+W2 < R1+W1)
1207 * \param theL2 Half-length of incident pipe
1208 * \param theHexMesh Boolean indicating if shape is prepared for hex mesh
1209 * \return List of GEOM_Objects, containing the created shape and propagation groups.
1211 //=============================================================================
1212 Handle(TColStd_HSequenceOfTransient)
1213 GEOMImpl_IAdvancedOperations::MakePipeTShape(double theR1, double theW1, double theL1,
1214 double theR2, double theW2, double theL2,
1217 MESSAGE("GEOMImpl_IAdvancedOperations::MakePipeTShape");
1220 Handle(GEOM_Object) aShape = GetEngine()->AddObject(GetDocID(), GEOM_TSHAPE);
1222 //Add a new shape function with parameters
1223 Handle(GEOM_Function) aFunction = aShape->AddFunction(GEOMImpl_PipeTShapeDriver::GetID(), TSHAPE_BASIC);
1224 if (aFunction.IsNull()) return NULL;
1226 //Check if the function is set correctly
1227 if (aFunction->GetDriverGUID() != GEOMImpl_PipeTShapeDriver::GetID()) return NULL;
1229 GEOMImpl_IPipeTShape aData(aFunction);
1237 aData.SetHexMesh(theHexMesh);
1239 //Compute the resulting value
1241 #if OCC_VERSION_LARGE > 0x06010000
1244 if (!GetSolver()->ComputeFunction(aFunction)) {
1245 SetErrorCode("TShape driver failed");
1249 if (!MakePipeTShapePartition(aShape, theR1, theW1, theL1, theR2, theW2, theL2))
1251 if (!MakePipeTShapeMirrorAndGlue(aShape, theR1, theW1, theL1, theR2, theW2, theL2))
1254 } catch (Standard_Failure) {
1255 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1256 SetErrorCode(aFail->GetMessageString());
1261 Handle(TColStd_HSequenceOfTransient) aSeq = new TColStd_HSequenceOfTransient;
1262 aSeq->Append(aShape);
1266 * Get the groups: BEGIN
1269 if (!MakeGroups(aShape, TSHAPE_BASIC, theR1, theW1, theL1, theR2, theW2, theL2, aSeq, gp_Trsf()))
1272 catch (Standard_Failure) {
1273 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1274 SetErrorCode(aFail->GetMessageString());
1278 TCollection_AsciiString aListRes, anEntry;
1279 // Iterate over the sequence aSeq
1280 Standard_Integer aNbGroups = aSeq->Length();
1281 Standard_Integer i = 2;
1282 for (; i <= aNbGroups; i++) {
1283 Handle(Standard_Transient) anItem = aSeq->Value(i);
1284 if (anItem.IsNull()) continue;
1285 Handle(GEOM_Object) aGroup = Handle(GEOM_Object)::DownCast(anItem);
1286 if (aGroup.IsNull()) continue;
1287 //Make a Python command
1288 TDF_Tool::Entry(aGroup->GetEntry(), anEntry);
1289 aListRes += anEntry + ", ";
1292 aListRes.Trunc(aListRes.Length() - 2);
1294 //Make a Python command
1295 GEOM::TPythonDump(aFunction)
1296 << "[" << aShape << ", " << aListRes.ToCString() << "] = geompy.MakePipeTShape("
1297 << theR1 << ", " << theW1 << ", " << theL1 << ", " << theR2 << ", " << theW2 << ", " << theL2 << ", "
1298 << theHexMesh << ")";
1301 * Get the groups: END
1304 //Make a Python command
1305 GEOM::TPythonDump(aFunction)
1306 << "[" << aShape << "] = geompy.MakePipeTShape(" << theR1 << ", " << theW1 << ", "
1307 << theL1 << ", " << theR2 << ", " << theW2 << ", " << theL2 << ", " << theHexMesh << ")";
1315 //=============================================================================
1317 * MakePipeTShapeWithPosition
1318 * Create a T-shape object with specified caracteristics for the main and
1319 * the incident pipes (radius, width, half-length).
1320 * The extremities of the main pipe are located on junctions points P1 and P2.
1321 * The extremity of the incident pipe is located on junction point P3.
1322 * \param theR1 Internal radius of main pipe
1323 * \param theW1 Width of main pipe
1324 * \param theL1 Half-length of main pipe
1325 * \param theR2 Internal radius of incident pipe (R2 < R1)
1326 * \param theW2 Width of incident pipe (R2+W2 < R1+W1)
1327 * \param theL2 Half-length of incident pipe
1328 * \param theHexMesh Boolean indicating if shape is prepared for hex mesh
1329 * \param theP1 1st junction point of main pipe
1330 * \param theP2 2nd junction point of main pipe
1331 * \param theP3 Junction point of incident pipe
1332 * \return List of GEOM_Objects, containing the created shape and propagation groups..
1334 //=============================================================================
1335 Handle(TColStd_HSequenceOfTransient)
1336 GEOMImpl_IAdvancedOperations::MakePipeTShapeWithPosition(double theR1, double theW1, double theL1,
1337 double theR2, double theW2, double theL2,
1339 Handle(GEOM_Object) theP1,
1340 Handle(GEOM_Object) theP2,
1341 Handle(GEOM_Object) theP3)
1345 Handle(GEOM_Object) aShape = GetEngine()->AddObject(GetDocID(), GEOM_TSHAPE);
1349 //Add a new shape function with parameters
1350 Handle(GEOM_Function) aFunction = aShape->AddFunction(GEOMImpl_PipeTShapeDriver::GetID(), TSHAPE_BASIC);
1351 if (aFunction.IsNull()) return NULL;
1353 //Check if the function is set correctly
1354 if (aFunction->GetDriverGUID() != GEOMImpl_PipeTShapeDriver::GetID()) return NULL;
1356 // Check new position
1357 if (!CheckCompatiblePosition(theL1, theL2, theP1, theP2, theP3, 0.01)) {
1361 GEOMImpl_IPipeTShape aData(aFunction);
1369 aData.SetHexMesh(theHexMesh);
1371 //Compute the resulting value
1373 #if OCC_VERSION_LARGE > 0x06010000
1376 if (!GetSolver()->ComputeFunction(aFunction)) {
1377 SetErrorCode("TShape driver failed");
1380 } catch (Standard_Failure) {
1381 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1382 SetErrorCode(aFail->GetMessageString());
1387 if (!MakePipeTShapePartition(aShape, theR1, theW1, theL1, theR2, theW2, theL2))
1389 if (!MakePipeTShapeMirrorAndGlue(aShape, theR1, theW1, theL1, theR2, theW2, theL2))
1393 TopoDS_Shape Te = aShape->GetValue();
1396 gp_Trsf aTrsf = GetPositionTrsf(theL1, theL2, theP1, theP2, theP3);
1397 BRepBuilderAPI_Transform aTransformation(Te, aTrsf, Standard_False);
1398 TopoDS_Shape aTrsf_Shape = aTransformation.Shape();
1399 aFunction->SetValue(aTrsf_Shape);
1400 Handle(TColStd_HSequenceOfTransient) aSeq = new TColStd_HSequenceOfTransient;
1401 aSeq->Append(aShape);
1405 // Get the groups: BEGIN
1408 if (!MakeGroups(aShape,TSHAPE_BASIC, theR1, theW1, theL1, theR2, theW2, theL2, aSeq, aTrsf)) {
1412 catch (Standard_Failure) {
1413 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1414 SetErrorCode(aFail->GetMessageString());
1418 TCollection_AsciiString aListRes, anEntry;
1419 // Iterate over the sequence aSeq
1420 Standard_Integer aNbGroups = aSeq->Length();
1421 Standard_Integer i = 2;
1422 for (; i <= aNbGroups; i++) {
1423 Handle(Standard_Transient) anItem = aSeq->Value(i);
1424 if (anItem.IsNull()) continue;
1425 Handle(GEOM_Object) aGroup = Handle(GEOM_Object)::DownCast(anItem);
1426 if (aGroup.IsNull()) continue;
1427 //Make a Python command
1428 TDF_Tool::Entry(aGroup->GetEntry(), anEntry);
1429 aListRes += anEntry + ", ";
1432 aListRes.Trunc(aListRes.Length() - 2);
1434 //Make a Python command
1435 GEOM::TPythonDump(aFunction)
1436 << "[" << aShape << ", " << aListRes.ToCString() << "] = geompy.MakePipeTShape("
1437 << theR1 << ", " << theW1 << ", " << theL1 << ", " << theR2 << ", " << theW2 << ", " << theL2 << ", "
1438 << theHexMesh << ", " << theP1 << ", " << theP2 << ", " << theP3 << ")";
1441 // Get the groups: END
1445 //Make a Python command
1446 GEOM::TPythonDump(aFunction)
1447 << "[" << aShape << "] = geompy.MakePipeTShape(" << theR1 << ", " << theW1 << ", "
1448 << theL1 << ", " << theR2 << ", " << theW2 << ", " << theL2 << ", " << theHexMesh << ", " << theP1
1449 << ", " << theP2 << ", " << theP3 << ")";
1457 //=============================================================================
1459 * MakePipeTShapeChamfer
1460 * Create a T-shape object with specified caracteristics for the main and
1461 * the incident pipes (radius, width, half-length). A chamfer is created
1462 * on the junction of the pipes.
1463 * Center of the shape is (0,0,0). The main plane of the T-shape is XOY.
1464 * \param theR1 Internal radius of main pipe
1465 * \param theW1 Width of main pipe
1466 * \param theL1 Half-length of main pipe
1467 * \param theR2 Internal radius of incident pipe (R2 < R1)
1468 * \param theW2 Width of incident pipe (R2+W2 < R1+W1)
1469 * \param theL2 Half-length of incident pipe
1470 * \param theH Height of chamfer.
1471 * \param theW Width of chamfer.
1472 * \param theHexMesh Boolean indicating if shape is prepared for hex mesh
1473 * \return List of GEOM_Objects, containing the created shape and propagation groups.
1475 //=============================================================================
1476 Handle(TColStd_HSequenceOfTransient)
1477 GEOMImpl_IAdvancedOperations::MakePipeTShapeChamfer(double theR1, double theW1, double theL1,
1478 double theR2, double theW2, double theL2,
1479 double theH, double theW,
1484 Handle(GEOM_Object) aShape = GetEngine()->AddObject(GetDocID(), GEOM_TSHAPE);
1485 //Add a new shape function with parameters
1486 Handle(GEOM_Function) aFunction = aShape->AddFunction(GEOMImpl_PipeTShapeDriver::GetID(), TSHAPE_CHAMFER);
1487 if (aFunction.IsNull()) return NULL;
1489 //Check if the function is set correctly
1490 if (aFunction->GetDriverGUID() != GEOMImpl_PipeTShapeDriver::GetID()) return NULL;
1492 GEOMImpl_IPipeTShape aData(aFunction);
1502 aData.SetHexMesh(theHexMesh);
1504 //Compute the resulting value
1506 #if OCC_VERSION_LARGE > 0x06010000
1509 if (!GetSolver()->ComputeFunction(aFunction)) {
1510 SetErrorCode("TShape driver failed");
1513 } catch (Standard_Failure) {
1514 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1515 SetErrorCode(aFail->GetMessageString());
1520 TopoDS_Shape aShapeShape = aShape->GetValue();
1521 TopTools_IndexedMapOfShape anEdgesIndices;
1522 TopExp::MapShapes(aShapeShape, anEdgesIndices);
1523 // Common edges on external cylinders
1524 Handle(GEOM_Object) box_e;
1526 box_e = my3DPrimOperations->MakeBoxDXDYDZ(theR2+theW2, theR2+theW2, theR1+theW1);
1529 box_e = my3DPrimOperations->MakeBoxDXDYDZ(2*(theR2+theW2), 2*(theR2+theW2), theR1+theW1);
1531 box_e->GetLastFunction()->SetDescription("");
1532 box_e = myTransformOperations->TranslateDXDYDZ(box_e, -(theR2+theW2), -(theR2+theW2), 0);
1533 box_e->GetLastFunction()->SetDescription("");
1535 Handle(TColStd_HSequenceOfInteger) edges_e =
1536 myShapesOperations->GetShapesOnBoxIDs(box_e, aShape, TopAbs_EDGE, GEOMAlgo_ST_IN);
1537 box_e->GetLastFunction()->SetDescription("");
1539 if (edges_e.IsNull() || edges_e->Length() == 0) {
1540 SetErrorCode("External edges not found");
1543 int nbEdgesInChamfer = 0;
1544 std::list<int> theEdges;
1545 for (int i=1; i<=edges_e->Length();i++) {
1546 int edgeID = edges_e->Value(i);
1547 TopoDS_Shape theEdge = anEdgesIndices.FindKey(edgeID);
1548 TopExp_Explorer Ex(theEdge,TopAbs_VERTEX);
1552 gp_Pnt aPt = BRep_Tool::Pnt(TopoDS::Vertex(Ex.Current()));
1553 if (Abs(aPt.Z() - (theR1+theW1)) <= Precision::Confusion()) {
1554 nbEdgesInChamfer ++;
1555 theEdges.push_back(edgeID);
1559 if (theHexMesh && nbEdgesInChamfer == 1)
1562 Handle(GEOM_Object) aChamfer;
1564 aChamfer = myLocalOperations->MakeChamferEdges(aShape, theW, theH, theEdges);
1566 catch (Standard_Failure) {
1567 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1568 SetErrorCode(aFail->GetMessageString());
1571 if (aChamfer.IsNull()) {
1572 SetErrorCode("Chamfer can not be computed on the given shape with the given parameters");
1575 aChamfer->GetLastFunction()->SetDescription("");
1577 TopoDS_Shape aChamferShape = aChamfer->GetValue();
1578 aFunction->SetValue(aChamferShape);
1581 // bool doMesh = false;
1584 if (!MakePipeTShapePartition(aShape, theR1, theW1, theL1, theR2, theW2, theL2, theH, theW, 0, false)) {
1585 MESSAGE("PipeTShape partition failed");
1589 if (!MakePipeTShapeMirrorAndGlue(aShape, theR1, theW1, theL1, theR2, theW2, theL2)) {
1590 MESSAGE("PipeTShape mirrors and glue failed");
1596 Handle(TColStd_HSequenceOfTransient) aSeq = new TColStd_HSequenceOfTransient;
1597 aSeq->Append(aShape);
1602 // Get the groups: BEGIN
1604 //if (!MakeGroups(aShape, TSHAPE_CHAMFER, theR1, theW1, theL1, theR2, theW2, theL2, aSeq, gp_Trsf())) {
1605 // //Make a Python command
1606 // GEOM::TPythonDump(aFunction)
1607 // << "[" << aShape << "] = geompy.MakePipeTShapeChamfer(" << theR1 << ", " << theW1
1608 // << ", " << theL1 << ", " << theR2 << ", " << theW2 << ", " << theL2 << ", " << theH << ", " << theW
1609 // << ", " << theHexMesh << ")";
1613 if (!MakeGroups(aShape, TSHAPE_CHAMFER, theR1, theW1, theL1, theR2, theW2, theL2, aSeq, gp_Trsf()))
1616 catch (Standard_Failure) {
1617 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1618 SetErrorCode(aFail->GetMessageString());
1622 TCollection_AsciiString aListRes, anEntry;
1623 // Iterate over the sequence aSeq
1624 Standard_Integer aNbGroups = aSeq->Length();
1625 Standard_Integer i = 2;
1626 for (; i <= aNbGroups; i++) {
1627 Handle(Standard_Transient) anItem = aSeq->Value(i);
1628 if (anItem.IsNull()) continue;
1629 Handle(GEOM_Object) aGroup = Handle(GEOM_Object)::DownCast(anItem);
1630 if (aGroup.IsNull()) continue;
1631 //Make a Python command
1632 TDF_Tool::Entry(aGroup->GetEntry(), anEntry);
1633 aListRes += anEntry + ", ";
1636 aListRes.Trunc(aListRes.Length() - 2);
1638 //Make a Python command
1639 GEOM::TPythonDump(aFunction)
1640 << "[" << aShape << ", " << aListRes.ToCString()
1641 << "] = geompy.MakePipeTShapeChamfer(" << theR1 << ", " << theW1 << ", " << theL1 << ", " << theR2
1642 << ", " << theW2 << ", " << theL2 << ", " << theH << ", " << theW << ", " << theHexMesh << ")";
1646 // Get the groups: END
1649 //Make a Python command
1650 GEOM::TPythonDump(aFunction)
1651 << "[" << aShape << "] = geompy.MakePipeTShapeChamfer(" << theR1 << ", " << theW1
1652 << ", " << theL1 << ", " << theR2 << ", " << theW2 << ", " << theL2 << ", " << theH << ", " << theW
1653 << ", " << theHexMesh << ")";
1661 //=============================================================================
1663 * MakePipeTShapeChamferWithPosition
1664 * Create a T-shape object with specified caracteristics for the main and
1665 * the incident pipes (radius, width, half-length). A chamfer is created
1666 * on the junction of the pipes.
1667 * The extremities of the main pipe are located on junctions points P1 and P2.
1668 * The extremity of the incident pipe is located on junction point P3.
1669 * \param theR1 Internal radius of main pipe
1670 * \param theW1 Width of main pipe
1671 * \param theL1 Half-length of main pipe
1672 * \param theR2 Internal radius of incident pipe (R2 < R1)
1673 * \param theW2 Width of incident pipe (R2+W2 < R1+W1)
1674 * \param theL2 Half-length of incident pipe
1675 * \param theH Height of chamfer.
1676 * \param theW Width of chamfer.
1677 * \param theHexMesh Boolean indicating if shape is prepared for hex mesh
1678 * \param theP1 1st junction point of main pipe
1679 * \param theP2 2nd junction point of main pipe
1680 * \param theP3 Junction point of incident pipe
1681 * \return List of GEOM_Objects, containing the created shape and propagation groups.
1683 //=============================================================================
1684 Handle(TColStd_HSequenceOfTransient)
1685 GEOMImpl_IAdvancedOperations::MakePipeTShapeChamferWithPosition(double theR1, double theW1, double theL1,
1686 double theR2, double theW2, double theL2,
1687 double theH, double theW,
1689 Handle(GEOM_Object) theP1,
1690 Handle(GEOM_Object) theP2,
1691 Handle(GEOM_Object) theP3)
1695 Handle(GEOM_Object) aShape = GetEngine()->AddObject(GetDocID(), GEOM_TSHAPE);
1696 //Add a new shape function with parameters
1697 Handle(GEOM_Function) aFunction = aShape->AddFunction(GEOMImpl_PipeTShapeDriver::GetID(), TSHAPE_CHAMFER);
1698 if (aFunction.IsNull()) return NULL;
1700 //Check if the function is set correctly
1701 if (aFunction->GetDriverGUID() != GEOMImpl_PipeTShapeDriver::GetID()) return NULL;
1703 // Check new position
1704 if (!CheckCompatiblePosition(theL1, theL2, theP1, theP2, theP3, 0.01)) {
1708 GEOMImpl_IPipeTShape aData(aFunction);
1718 aData.SetHexMesh(theHexMesh);
1720 //Compute the resulting value
1722 #if OCC_VERSION_LARGE > 0x06010000
1725 if (!GetSolver()->ComputeFunction(aFunction)) {
1726 SetErrorCode("TShape driver failed");
1729 } catch (Standard_Failure) {
1730 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1731 SetErrorCode(aFail->GetMessageString());
1736 TopoDS_Shape aShapeShape = aShape->GetValue();
1737 TopTools_IndexedMapOfShape anEdgesIndices;
1738 TopExp::MapShapes(aShapeShape, anEdgesIndices);
1739 // Common edges on external cylinders
1740 Handle(GEOM_Object) box_e;
1742 box_e = my3DPrimOperations->MakeBoxDXDYDZ(theR2+theW2, theR2+theW2, theR1+theW1);
1745 box_e = my3DPrimOperations->MakeBoxDXDYDZ(2*(theR2+theW2), 2*(theR2+theW2), theR1+theW1);
1747 box_e->GetLastFunction()->SetDescription("");
1748 box_e = myTransformOperations->TranslateDXDYDZ(box_e, -(theR2+theW2), -(theR2+theW2), 0);
1749 box_e->GetLastFunction()->SetDescription("");
1751 Handle(TColStd_HSequenceOfInteger) edges_e =
1752 myShapesOperations->GetShapesOnBoxIDs(box_e, aShape, TopAbs_EDGE, GEOMAlgo_ST_IN);
1753 box_e->GetLastFunction()->SetDescription("");
1755 if (edges_e.IsNull() || edges_e->Length() == 0) {
1756 SetErrorCode("External edges not found");
1759 int nbEdgesInChamfer = 0;
1760 std::list<int> theEdges;
1761 for (int i=1; i<=edges_e->Length();i++) {
1762 int edgeID = edges_e->Value(i);
1763 TopoDS_Shape theEdge = anEdgesIndices.FindKey(edgeID);
1764 TopExp_Explorer Ex(theEdge,TopAbs_VERTEX);
1766 gp_Pnt aPt = BRep_Tool::Pnt(TopoDS::Vertex(Ex.Current()));
1767 if (Abs(aPt.Z() - (theR1+theW1)) <= Precision::Confusion()) {
1768 nbEdgesInChamfer ++;
1769 theEdges.push_back(edgeID);
1773 if (theHexMesh && nbEdgesInChamfer == 1)
1776 Handle(GEOM_Object) aChamfer;
1778 aChamfer = myLocalOperations->MakeChamferEdges(aShape, theW, theH, theEdges);
1780 catch (Standard_Failure) {
1781 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1782 SetErrorCode(aFail->GetMessageString());
1785 if (aChamfer.IsNull()) {
1786 SetErrorCode("Chamfer can not be computed on the given shape with the given parameters");
1789 aChamfer->GetLastFunction()->SetDescription("");
1791 TopoDS_Shape aChamferShape = aChamfer->GetValue();
1792 aFunction->SetValue(aChamferShape);
1796 if (!MakePipeTShapePartition(aShape, theR1, theW1, theL1, theR2, theW2, theL2, theH, theW, 0, false))
1798 if (!MakePipeTShapeMirrorAndGlue(aShape, theR1, theW1, theL1, theR2, theW2, theL2))
1802 TopoDS_Shape Te = aShape->GetValue();
1805 gp_Trsf aTrsf = GetPositionTrsf(theL1, theL2, theP1, theP2, theP3);
1806 BRepBuilderAPI_Transform aTransformation(Te, aTrsf, Standard_False);
1807 TopoDS_Shape aTrsf_Shape = aTransformation.Shape();
1808 aFunction->SetValue(aTrsf_Shape);
1809 Handle(TColStd_HSequenceOfTransient) aSeq = new TColStd_HSequenceOfTransient;
1810 aSeq->Append(aShape);
1813 * Get the groups: BEGIN
1816 if (!MakeGroups(aShape, TSHAPE_CHAMFER, theR1, theW1, theL1, theR2, theW2, theL2, aSeq, aTrsf))
1819 catch (Standard_Failure) {
1820 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1821 SetErrorCode(aFail->GetMessageString());
1825 TCollection_AsciiString aListRes, anEntry;
1826 // Iterate over the sequence aSeq
1827 Standard_Integer aNbGroups = aSeq->Length();
1828 Standard_Integer i = 2;
1829 for (; i <= aNbGroups; i++) {
1830 Handle(Standard_Transient) anItem = aSeq->Value(i);
1831 if (anItem.IsNull()) continue;
1832 Handle(GEOM_Object) aGroup = Handle(GEOM_Object)::DownCast(anItem);
1833 if (aGroup.IsNull()) continue;
1834 //Make a Python command
1835 TDF_Tool::Entry(aGroup->GetEntry(), anEntry);
1836 aListRes += anEntry + ", ";
1839 aListRes.Trunc(aListRes.Length() - 2);
1841 //Make a Python command
1842 GEOM::TPythonDump(aFunction)
1843 << "[" << aShape << ", " << aListRes.ToCString()
1844 << "] = geompy.MakePipeTShapeChamfer(" << theR1 << ", " << theW1 << ", " << theL1 << ", " << theR2
1845 << ", " << theW2 << ", " << theL2 << ", " << theH << ", " << theW << ", " << theHexMesh << ", "
1846 << theP1 << ", " << theP2 << ", " << theP3 << ")";
1849 * Get the groups: END
1852 //Make a Python command
1853 GEOM::TPythonDump(aFunction)
1854 << "[" << aShape << "] = geompy.MakePipeTShapeChamfer(" << theR1 << ", " << theW1
1855 << ", " << theL1 << ", " << theR2 << ", " << theW2 << ", " << theL2 << ", " << theH << ", " << theW
1856 << ", " << theHexMesh << ", " << theP1 << ", " << theP2 << ", " << theP3 << ")";
1864 //=============================================================================
1866 * MakePipeTShapeFillet
1867 * Create a T-shape object with specified caracteristics for the main and
1868 * the incident pipes (radius, width, half-length). A fillet is created
1869 * on the junction of the pipes.
1870 * Center of the shape is (0,0,0). The main plane of the T-shape is XOY.
1871 * \param theR1 Internal radius of main pipe
1872 * \param theW1 Width of main pipe
1873 * \param theL1 Half-length of main pipe
1874 * \param theR2 Internal radius of incident pipe (R2 < R1)
1875 * \param theW2 Width of incident pipe (R2+W2 < R1+W1)
1876 * \param theL2 Half-length of incident pipe
1877 * \param theRF Radius of curvature of fillet.
1878 * \param theHexMesh Boolean indicating if shape is prepared for hex mesh
1879 * \return List of GEOM_Objects, containing the created shape and propagation groups.
1881 //=============================================================================
1882 Handle(TColStd_HSequenceOfTransient)
1883 GEOMImpl_IAdvancedOperations::MakePipeTShapeFillet(double theR1, double theW1, double theL1,
1884 double theR2, double theW2, double theL2,
1885 double theRF, bool theHexMesh)
1889 Handle(GEOM_Object) aShape = GetEngine()->AddObject(GetDocID(), GEOM_TSHAPE);
1890 //Add a new shape function with parameters
1891 Handle(GEOM_Function) aFunction = aShape->AddFunction(GEOMImpl_PipeTShapeDriver::GetID(), TSHAPE_FILLET);
1892 if (aFunction.IsNull()) return NULL;
1894 //Check if the function is set correctly
1895 if (aFunction->GetDriverGUID() != GEOMImpl_PipeTShapeDriver::GetID()) return NULL;
1897 GEOMImpl_IPipeTShape aData(aFunction);
1906 aData.SetHexMesh(theHexMesh);
1908 //Compute the resulting value
1910 #if OCC_VERSION_LARGE > 0x06010000
1913 if (!GetSolver()->ComputeFunction(aFunction)) {
1914 SetErrorCode("TShape driver failed");
1917 } catch (Standard_Failure) {
1918 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1919 SetErrorCode(aFail->GetMessageString());
1924 TopoDS_Shape aShapeShape = aShape->GetValue();
1925 TopTools_IndexedMapOfShape anEdgesIndices;
1926 TopExp::MapShapes(aShapeShape, anEdgesIndices);
1927 // Common edges on external cylinders
1928 Handle(GEOM_Object) box_e;
1930 box_e = my3DPrimOperations->MakeBoxDXDYDZ(theR2+theW2, theR2+theW2, theR1+theW1);
1933 box_e = my3DPrimOperations->MakeBoxDXDYDZ(2*(theR2+theW2), 2*(theR2+theW2), theR1+theW1);
1935 box_e->GetLastFunction()->SetDescription("");
1936 box_e = myTransformOperations->TranslateDXDYDZ(box_e, -(theR2+theW2), -(theR2+theW2), 0);
1937 box_e->GetLastFunction()->SetDescription("");
1939 Handle(TColStd_HSequenceOfInteger) edges_e =
1940 myShapesOperations->GetShapesOnBoxIDs(box_e, aShape, TopAbs_EDGE, GEOMAlgo_ST_IN);
1941 box_e->GetLastFunction()->SetDescription("");
1943 if (edges_e.IsNull() || edges_e->Length() == 0) {
1944 SetErrorCode("External edges not found");
1947 int nbEdgesInFillet = 0;
1948 std::list<int> theEdges;
1949 for (int i=1; i<=edges_e->Length();i++) {
1950 int edgeID = edges_e->Value(i);
1951 TopoDS_Shape theEdge = anEdgesIndices.FindKey(edgeID);
1952 TopExp_Explorer Ex(theEdge,TopAbs_VERTEX);
1954 gp_Pnt aPt = BRep_Tool::Pnt(TopoDS::Vertex(Ex.Current()));
1955 if (Abs(aPt.Z() - (theR1+theW1)) <= Precision::Confusion()) {
1957 theEdges.push_back(edgeID);
1961 if (theHexMesh && nbEdgesInFillet == 1)
1965 Handle(GEOM_Object) aFillet;
1967 aFillet = myLocalOperations->MakeFilletEdges(aShape, theRF, theEdges);
1969 catch (Standard_Failure) {
1970 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1971 SetErrorCode(aFail->GetMessageString());
1974 if (aFillet.IsNull()) {
1975 //SetErrorCode("Fillet can not be computed on the given shape with the given parameters");
1976 SetErrorCode(myLocalOperations->GetErrorCode());
1979 aFillet->GetLastFunction()->SetDescription("");
1981 TopoDS_Shape aFilletShape = aFillet->GetValue();
1982 aFunction->SetValue(aFilletShape);
1985 // VSR: debug issues 0021568 and 0021550 (15/05/2012) - BEGIN (1)
1986 // the following block, when enabled, leads to partitioning problems
1988 // VSR: debug issues 0021568 and 0021550 (15/05/2012) - END (1)
1989 // BEGIN: Limit tolerances (debug)
1990 Handle(GEOM_Object) aCorr1 = myHealingOperations->LimitTolerance(aShape, 1e-07);
1991 TopoDS_Shape aCorr1Shape = aCorr1->GetValue();
1992 aShape->GetLastFunction()->SetValue(aCorr1Shape);
1993 aCorr1->GetLastFunction()->SetDescription("");
1994 // END: Limit tolerances (debug)
1995 // VSR: debug issues 0021568 and 0021550 (15/05/2012) - BEGIN (2)
1997 // VSR: debug issues 0021568 and 0021550 (15/05/2012) - END (2)
2000 if (!MakePipeTShapePartition(aShape, theR1, theW1, theL1, theR2, theW2, theL2, 0, 0, theRF, false))
2002 if (!MakePipeTShapeMirrorAndGlue(aShape, theR1, theW1, theL1, theR2, theW2, theL2))
2006 Handle(TColStd_HSequenceOfTransient) aSeq = new TColStd_HSequenceOfTransient;
2007 aSeq->Append(aShape);
2010 * Get the groups: BEGIN
2013 if (!MakeGroups(aShape, TSHAPE_FILLET, theR1, theW1, theL1, theR2, theW2, theL2, aSeq, gp_Trsf()))
2016 catch (Standard_Failure) {
2017 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
2018 SetErrorCode(aFail->GetMessageString());
2022 TCollection_AsciiString aListRes, anEntry;
2023 // Iterate over the sequence aSeq
2024 Standard_Integer aNbGroups = aSeq->Length();
2025 Standard_Integer i = 2;
2026 for (; i <= aNbGroups; i++) {
2027 Handle(Standard_Transient) anItem = aSeq->Value(i);
2028 if (anItem.IsNull()) continue;
2029 Handle(GEOM_Object) aGroup = Handle(GEOM_Object)::DownCast(anItem);
2030 if (aGroup.IsNull()) continue;
2031 //Make a Python command
2032 TDF_Tool::Entry(aGroup->GetEntry(), anEntry);
2033 aListRes += anEntry + ", ";
2036 aListRes.Trunc(aListRes.Length() - 2);
2038 //Make a Python command
2039 GEOM::TPythonDump(aFunction)
2040 << "[" << aShape << ", " << aListRes.ToCString()
2041 << "] = geompy.MakePipeTShapeFillet(" << theR1 << ", " << theW1 << ", " << theL1 << ", " << theR2
2042 << ", " << theW2 << ", " << theL2 << ", " << theRF << ", " << theHexMesh << ")";
2045 * Get the groups: END
2048 //Make a Python command
2049 GEOM::TPythonDump(aFunction)
2050 << "[" << aShape << "] = geompy.MakePipeTShapeFillet(" << theR1 << ", " << theW1
2051 << ", " << theL1 << ", " << theR2 << ", " << theW2 << ", " << theL2 << ", " << theRF << ", "
2052 << theHexMesh << ")";
2060 //=============================================================================
2062 * MakePipeTShapeFilletWithPosition
2063 * \brief Create a T-shape object with specified caracteristics for the main and
2064 * the incident pipes (radius, width, half-length). A fillet is created
2065 * on the junction of the pipes.
2066 * The extremities of the main pipe are located on junctions points P1 and P2.
2067 * The extremity of the incident pipe is located on junction point P3.
2068 * \param theR1 Internal radius of main pipe
2069 * \param theW1 Width of main pipe
2070 * \param theL1 Half-length of main pipe
2071 * \param theR2 Internal radius of incident pipe (R2 < R1)
2072 * \param theW2 Width of incident pipe (R2+W2 < R1+W1)
2073 * \param theL2 Half-length of incident pipe
2074 * \param theRF Radius of curvature of fillet
2075 * \param theHexMesh Boolean indicating if shape is prepared for hex mesh
2076 * \param theP1 1st junction point of main pipe
2077 * \param theP2 2nd junction point of main pipe
2078 * \param theP3 Junction point of incident pipe
2079 * \return List of GEOM_Objects, containing the created shape and propagation groups.
2081 //=============================================================================
2082 Handle(TColStd_HSequenceOfTransient)
2083 GEOMImpl_IAdvancedOperations::MakePipeTShapeFilletWithPosition(double theR1, double theW1, double theL1,
2084 double theR2, double theW2, double theL2,
2085 double theRF, bool theHexMesh,
2086 Handle(GEOM_Object) theP1,
2087 Handle(GEOM_Object) theP2,
2088 Handle(GEOM_Object) theP3)
2092 Handle(GEOM_Object) aShape = GetEngine()->AddObject(GetDocID(), GEOM_TSHAPE);
2093 //Add a new shape function with parameters
2094 Handle(GEOM_Function) aFunction = aShape->AddFunction(GEOMImpl_PipeTShapeDriver::GetID(), TSHAPE_FILLET);
2095 if (aFunction.IsNull()) return NULL;
2097 //Check if the function is set correctly
2098 if (aFunction->GetDriverGUID() != GEOMImpl_PipeTShapeDriver::GetID()) return NULL;
2100 // Check new position
2101 if (!CheckCompatiblePosition(theL1, theL2, theP1, theP2, theP3, 0.01)) {
2105 GEOMImpl_IPipeTShape aData(aFunction);
2114 aData.SetHexMesh(theHexMesh);
2116 //Compute the resulting value
2118 #if OCC_VERSION_LARGE > 0x06010000
2121 if (!GetSolver()->ComputeFunction(aFunction)) {
2122 SetErrorCode("TShape driver failed");
2125 } catch (Standard_Failure) {
2126 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
2127 SetErrorCode(aFail->GetMessageString());
2132 TopoDS_Shape aShapeShape = aShape->GetValue();
2133 TopTools_IndexedMapOfShape anEdgesIndices;
2134 TopExp::MapShapes(aShapeShape, anEdgesIndices);
2135 // Common edges on external cylinders
2136 Handle(GEOM_Object) box_e;
2138 box_e = my3DPrimOperations->MakeBoxDXDYDZ(theR2+theW2, theR2+theW2, theR1+theW1);
2141 box_e = my3DPrimOperations->MakeBoxDXDYDZ(2*(theR2+theW2), 2*(theR2+theW2), theR1+theW1);
2143 box_e->GetLastFunction()->SetDescription("");
2144 box_e = myTransformOperations->TranslateDXDYDZ(box_e, -(theR2+theW2), -(theR2+theW2), 0);
2145 box_e->GetLastFunction()->SetDescription("");
2147 Handle(TColStd_HSequenceOfInteger) edges_e =
2148 myShapesOperations->GetShapesOnBoxIDs(box_e, aShape, TopAbs_EDGE, GEOMAlgo_ST_IN);
2149 box_e->GetLastFunction()->SetDescription("");
2151 if (edges_e.IsNull() || edges_e->Length() == 0) {
2152 SetErrorCode("External edges not found");
2155 int nbEdgesInFillet = 0;
2156 std::list<int> theEdges;
2157 for (int i=1; i<=edges_e->Length();i++) {
2158 int edgeID = edges_e->Value(i);
2159 TopoDS_Shape theEdge = anEdgesIndices.FindKey(edgeID);
2160 TopExp_Explorer Ex(theEdge,TopAbs_VERTEX);
2162 gp_Pnt aPt = BRep_Tool::Pnt(TopoDS::Vertex(Ex.Current()));
2163 if (Abs(aPt.Z() - (theR1+theW1)) <= Precision::Confusion()) {
2165 theEdges.push_back(edgeID);
2169 if (theHexMesh && nbEdgesInFillet == 1)
2173 Handle(GEOM_Object) aFillet;
2175 aFillet = myLocalOperations->MakeFilletEdges(aShape, theRF, theEdges);
2177 catch (Standard_Failure) {
2178 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
2179 SetErrorCode(aFail->GetMessageString());
2182 if (aFillet.IsNull()) {
2183 SetErrorCode("Fillet can not be computed on the given shape with the given parameters");
2186 aFillet->GetLastFunction()->SetDescription("");
2188 TopoDS_Shape aFilletShape = aFillet->GetValue();
2189 aFunction->SetValue(aFilletShape);
2192 // VSR: debug issues 0021568 and 0021550 (15/05/2012) - BEGIN (3)
2193 // the following block, when enabled, leads to partitioning problems
2195 // VSR: debug issues 0021568 and 0021550 (15/05/2012) - END (3)
2196 // BEGIN: Limit tolerances (debug)
2197 Handle(GEOM_Object) aCorr1 = myHealingOperations->LimitTolerance(aShape, 1e-07);
2198 TopoDS_Shape aCorr1Shape = aCorr1->GetValue();
2199 aShape->GetLastFunction()->SetValue(aCorr1Shape);
2200 aCorr1->GetLastFunction()->SetDescription("");
2201 // END: Limit tolerances (debug)
2202 // VSR: debug issues 0021568 and 0021550 (15/05/2012) - BEGIN (4)
2204 // VSR: debug issues 0021568 and 0021550 (15/05/2012) - END (4)
2207 if (!MakePipeTShapePartition(aShape, theR1, theW1, theL1, theR2, theW2, theL2, 0, 0, theRF, false))
2209 if (!MakePipeTShapeMirrorAndGlue(aShape, theR1, theW1, theL1, theR2, theW2, theL2))
2213 TopoDS_Shape Te = aShape->GetValue();
2216 gp_Trsf aTrsf = GetPositionTrsf(theL1, theL2, theP1, theP2, theP3);
2217 BRepBuilderAPI_Transform aTransformation(Te, aTrsf, Standard_False);
2218 TopoDS_Shape aTrsf_Shape = aTransformation.Shape();
2219 aFunction->SetValue(aTrsf_Shape);
2220 Handle(TColStd_HSequenceOfTransient) aSeq = new TColStd_HSequenceOfTransient;
2221 aSeq->Append(aShape);
2224 * Get the groups: BEGIN
2227 if (!MakeGroups(aShape, TSHAPE_FILLET, theR1, theW1, theL1, theR2, theW2, theL2, aSeq, aTrsf))
2230 catch (Standard_Failure) {
2231 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
2232 SetErrorCode(aFail->GetMessageString());
2236 TCollection_AsciiString aListRes, anEntry;
2237 // Iterate over the sequence aSeq
2238 Standard_Integer aNbGroups = aSeq->Length();
2239 Standard_Integer i = 2;
2240 for (; i <= aNbGroups; i++) {
2241 Handle(Standard_Transient) anItem = aSeq->Value(i);
2242 if (anItem.IsNull()) continue;
2243 Handle(GEOM_Object) aGroup = Handle(GEOM_Object)::DownCast(anItem);
2244 if (aGroup.IsNull()) continue;
2245 //Make a Python command
2246 TDF_Tool::Entry(aGroup->GetEntry(), anEntry);
2247 aListRes += anEntry + ", ";
2250 aListRes.Trunc(aListRes.Length() - 2);
2252 //Make a Python command
2253 GEOM::TPythonDump(aFunction)
2254 << "[" << aShape << ", " << aListRes.ToCString()
2255 << "] = geompy.MakePipeTShapeFillet(" << theR1 << ", " << theW1 << ", " << theL1 << ", " << theR2
2256 << ", " << theW2 << ", " << theL2 << ", " << theRF << ", " << theHexMesh << ", " << theP1 << ", "
2257 << theP2 << ", " << theP3 << ")";
2260 * Get the groups: END
2263 //Make a Python command
2264 GEOM::TPythonDump(aFunction)
2265 << "[" << aShape << "] = geompy.MakePipeTShapeFillet(" << theR1 << ", " << theW1
2266 << ", " << theL1 << ", " << theR2 << ", " << theW2 << ", " << theL2 << ", " << theRF << ", "
2267 << theHexMesh << ", " << theP1 << ", " << theP2 << ", " << theP3 << ")";
2275 //=============================================================================
2277 * This function allows to create a disk already divided into blocks. It can be
2278 * used to create divided pipes for later meshing in hexaedra.
2279 * \param theR Radius of the disk
2280 * \param theRatio Relative size of the central square diagonal against the disk diameter
2281 * \param theOrientation Plane on which the disk will be built
2282 * \param thePattern The division pattern of the disk (hexagon or square in the center)
2283 * \return New GEOM_Object, containing the created shape.
2285 //=============================================================================
2286 Handle(GEOM_Object) GEOMImpl_IAdvancedOperations::MakeDividedDisk (double theR, double theRatio,
2287 int theOrientation, int thePattern)
2291 if (theOrientation != 1 &&
2292 theOrientation != 2 &&
2293 theOrientation != 3)
2295 SetErrorCode("theOrientation must be 1(=OXY), 2(=OYZ) or 3(=OZX)");
2299 Handle(GEOM_Object) aShape = GetEngine()->AddObject(GetDocID(), GEOM_DIVIDEDDISK);
2301 //Add a new shape function with parameters
2302 Handle(GEOM_Function) aFunction = aShape->AddFunction(GEOMImpl_DividedDiskDriver::GetID(), DIVIDEDDISK_R_RATIO);
2303 if (aFunction.IsNull()) return NULL;
2305 //Check if the function is set correctly
2306 if (aFunction->GetDriverGUID() != GEOMImpl_DividedDiskDriver::GetID()) return NULL;
2308 GEOMImpl_IDividedDisk aData (aFunction);
2311 aData.SetRatio(theRatio);
2312 aData.SetOrientation(theOrientation);
2313 aData.SetType(thePattern);
2315 //Compute the resulting value
2317 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
2320 if (!GetSolver()->ComputeFunction(aFunction)) {
2321 SetErrorCode("DividedDisk driver failed");
2325 catch (Standard_Failure) {
2326 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
2327 SetErrorCode(aFail->GetMessageString());
2331 std::string aPatternStr;
2336 aPatternStr = "GEOM.SQUARE";
2339 aPatternStr = "GEOM.HEXAGON";
2343 //Make a Python command
2344 GEOM::TPythonDump(aFunction) << aShape << " = geompy.MakeDividedDisk(" << theR << ", " << theOrientation << ", " << aPatternStr.c_str() << ")";
2351 //=============================================================================
2353 * This function allows to create a disk already divided into blocks. It can be
2354 * used to create divided pipes for later meshing in hexaedra.
2355 * \param theR Radius of the disk
2356 * \param theRatio Relative size of the central square diagonal against the disk diameter
2357 * \return New GEOM_Object, containing the created shape.
2359 //=============================================================================
2360 Handle(GEOM_Object) GEOMImpl_IAdvancedOperations::MakeDividedDiskPntVecR (Handle(GEOM_Object) thePnt,
2361 Handle(GEOM_Object) theVec,
2369 Handle(GEOM_Object) aShape = GetEngine()->AddObject(GetDocID(), GEOM_DIVIDEDDISK);
2371 //Add a new shape function with parameters
2372 Handle(GEOM_Function) aFunction = aShape->AddFunction(GEOMImpl_DividedDiskDriver::GetID(), DIVIDEDDISK_R_VECTOR_PNT);
2373 if (aFunction.IsNull()) return NULL;
2375 //Check if the function is set correctly
2376 if (aFunction->GetDriverGUID() != GEOMImpl_DividedDiskDriver::GetID()) return NULL;
2378 GEOMImpl_IDividedDisk aData (aFunction);
2380 Handle(GEOM_Function) aRefPnt = thePnt->GetLastFunction();
2381 Handle(GEOM_Function) aRefVec = theVec->GetLastFunction();
2383 if (aRefPnt.IsNull() || aRefVec.IsNull()) return NULL;
2385 aData.SetCenter(aRefPnt);
2386 aData.SetVector(aRefVec);
2389 aData.SetRatio(theRatio);
2390 aData.SetType(thePattern);
2392 //Compute the resulting value
2394 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
2397 if (!GetSolver()->ComputeFunction(aFunction)) {
2398 SetErrorCode("DividedDisk driver failed");
2402 catch (Standard_Failure) {
2403 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
2404 SetErrorCode(aFail->GetMessageString());
2408 std::string aPatternStr;
2413 aPatternStr = "GEOM.SQUARE";
2416 aPatternStr = "GEOM.HEXAGON";
2421 //Make a Python command
2422 GEOM::TPythonDump(aFunction) << aShape << " = geompy.MakeDividedDiskPntVecR(" << thePnt << ", " << theVec << ", " << theR << ", " << aPatternStr.c_str() << ")";
2429 //=============================================================================
2431 * Builds a cylinder prepared for hexa meshes
2432 * \param theR Radius of the cylinder
2433 * \param theH Height of the cylinder
2434 * \return New GEOM_Object, containing the created shape.
2436 //=============================================================================
2437 Handle(GEOM_Object) GEOMImpl_IAdvancedOperations::MakeDividedCylinder (double theR,
2444 Handle(GEOM_Object) aShape = GetEngine()->AddObject(GetDocID(), GEOM_DIVIDEDCYLINDER);
2446 Handle(GEOM_Object) aBaseShape = MakeDividedDisk(theR, 67.0, 1, thePattern);
2447 aBaseShape->GetLastFunction()->SetDescription(""); // Erase dump of MakeDividedDisk
2449 aShape = my3DPrimOperations->MakePrismDXDYDZ(aBaseShape,0.0,0.0,theH, -1.0);
2451 Handle(GEOM_Function) aFunction = aShape->GetLastFunction();
2452 aFunction->SetDescription(""); // Erase dump of MakePrismDXDYDZ
2453 aShape->SetType(GEOM_DIVIDEDCYLINDER);
2455 std::string aPatternStr;
2460 aPatternStr = "GEOM.SQUARE";
2463 aPatternStr = "GEOM.HEXAGON";
2467 //Make a Python command
2468 GEOM::TPythonDump(aFunction) << aShape << " = geompy.MakeDividedCylinder(" << theR << ", " << theH << ", " << aPatternStr.c_str() << ")";
2474 /*@@ insert new functions before this line @@ do not remove this line @@ do not remove this line @@*/