Salome HOME
Fix for Bug IPAL11055:
[modules/smesh.git] / src / SMESH / SMESH_MesherHelper.cxx
1 // Copyright (C) 2005  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
2 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
3 //
4 // This library is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU Lesser General Public
6 // License as published by the Free Software Foundation; either
7 // version 2.1 of the License.
8 //
9 // This library is distributed in the hope that it will be useful
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 // Lesser General Public License for more details.
13 //
14 // You should have received a copy of the GNU Lesser General Public
15 // License along with this library; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
17 //
18 // See http://www.salome-platform.org/
19 //
20 // File:      SMESH_MesherHelper.cxx
21 // Created:   15.02.06 15:22:41
22 // Author:    Sergey KUUL
23 // Copyright: Open CASCADE 2006
24
25
26 #include "SMESH_MesherHelper.hxx"
27
28 #include "SMDS_FacePosition.hxx" 
29 #include "SMDS_EdgePosition.hxx"
30 #include "SMESH_MeshEditor.hxx"
31
32 #include <BRepAdaptor_Surface.hxx>
33 #include <BRepTools.hxx>
34 #include <BRep_Tool.hxx>
35 #include <Geom2d_Curve.hxx>
36 #include <Geom_Curve.hxx>
37 #include <Geom_Surface.hxx>
38 #include <TopExp_Explorer.hxx>
39 #include <TopTools_MapOfShape.hxx>
40 #include <gp_Pnt2d.hxx>
41 #include <ShapeAnalysis.hxx>
42
43 //=======================================================================
44 //function : CheckShape
45 //purpose  : 
46 //=======================================================================
47
48 bool SMESH_MesherHelper::IsQuadraticSubMesh(const TopoDS_Shape& aSh)
49 {
50   SMESHDS_Mesh* meshDS = GetMesh()->GetMeshDS();
51   // we can create quadratic elements only if all elements
52   // created on subshapes of given shape are quadratic
53   // also we have to fill myNLinkNodeMap
54   myCreateQuadratic = true;
55   mySeamShapeIds.clear();
56   TopAbs_ShapeEnum subType( aSh.ShapeType()==TopAbs_FACE ? TopAbs_EDGE : TopAbs_FACE );
57   SMDSAbs_ElementType elemType( subType==TopAbs_FACE ? SMDSAbs_Face : SMDSAbs_Edge );
58
59   TopExp_Explorer exp( aSh, subType );
60   for (; exp.More() && myCreateQuadratic; exp.Next()) {
61     if ( SMESHDS_SubMesh * subMesh = meshDS->MeshElements( exp.Current() )) {
62       if ( SMDS_ElemIteratorPtr it = subMesh->GetElements() ) {
63         while(it->more()) {
64           const SMDS_MeshElement* e = it->next();
65           if ( e->GetType() != elemType || !e->IsQuadratic() ) {
66             myCreateQuadratic = false;
67             break;
68           }
69           else {
70             // fill NLinkNodeMap
71             switch ( e->NbNodes() ) {
72             case 3:
73               AddNLinkNode(e->GetNode(0),e->GetNode(1),e->GetNode(2)); break;
74             case 6:
75               AddNLinkNode(e->GetNode(0),e->GetNode(1),e->GetNode(3));
76               AddNLinkNode(e->GetNode(1),e->GetNode(2),e->GetNode(4));
77               AddNLinkNode(e->GetNode(2),e->GetNode(0),e->GetNode(5)); break;
78             case 8:
79               AddNLinkNode(e->GetNode(0),e->GetNode(1),e->GetNode(4));
80               AddNLinkNode(e->GetNode(1),e->GetNode(2),e->GetNode(5));
81               AddNLinkNode(e->GetNode(2),e->GetNode(3),e->GetNode(6));
82               AddNLinkNode(e->GetNode(3),e->GetNode(0),e->GetNode(7));
83               break;
84             default:
85               myCreateQuadratic = false;
86               break;
87             }
88           }
89         }
90       }
91     }
92   }
93
94   if(!myCreateQuadratic) {
95     myNLinkNodeMap.clear();
96   }
97   else {
98     SetSubShape( aSh );
99   }
100   return myCreateQuadratic;
101 }
102
103 //================================================================================
104 /*!
105  * \brief Set geomerty to make elements on
106   * \param aSh - geomertic shape
107  */
108 //================================================================================
109
110 void SMESH_MesherHelper::SetSubShape(const TopoDS_Shape& aSh)
111 {
112   SMESHDS_Mesh* meshDS = GetMesh()->GetMeshDS();
113
114   myShape = aSh;
115   myShapeID = meshDS->ShapeToIndex(aSh);
116
117   // treatment of periodic faces
118   if ( aSh.ShapeType() == TopAbs_FACE )
119   {
120     const TopoDS_Face& face = TopoDS::Face( aSh );
121     BRepAdaptor_Surface surface( face );
122     if ( surface.IsUPeriodic() || surface.IsVPeriodic() )
123     {
124       // look for a seam edge
125       for ( TopExp_Explorer exp( face, TopAbs_EDGE ); exp.More(); exp.Next()) {
126         const TopoDS_Edge& edge = TopoDS::Edge( exp.Current() );
127         if ( BRep_Tool::IsClosed( edge, face )) {
128           // initialize myPar1, myPar2 and myParIndex
129           if ( mySeamShapeIds.empty() ) {
130             gp_Pnt2d uv1, uv2;
131             BRep_Tool::UVPoints( edge, face, uv1, uv2 );
132             if ( Abs( uv1.Coord(1) - uv2.Coord(1) ) < Abs( uv1.Coord(2) - uv2.Coord(2) ))
133             {
134               myParIndex = 1; // U periodic
135               myPar1 = surface.FirstUParameter();
136               myPar2 = surface.LastUParameter();
137             }
138             else {
139               myParIndex = 2;  // V periodic
140               myPar1 = surface.FirstVParameter();
141               myPar2 = surface.LastVParameter();
142             }
143           }
144           // store shapes indices
145           mySeamShapeIds.insert( meshDS->ShapeToIndex( exp.Current() ));
146           for ( TopExp_Explorer v( exp.Current(), TopAbs_VERTEX ); v.More(); v.Next() )
147             mySeamShapeIds.insert( meshDS->ShapeToIndex( v.Current() ));
148         }
149       }
150     }
151   }
152 }
153
154
155 //=======================================================================
156 //function : IsMedium
157 //purpose  : 
158 //=======================================================================
159
160 bool SMESH_MesherHelper::IsMedium(const SMDS_MeshNode*      node,
161                                  const SMDSAbs_ElementType typeToCheck)
162 {
163   return SMESH_MeshEditor::IsMedium( node, typeToCheck );
164 }
165
166 //=======================================================================
167 //function : AddNLinkNode
168 //purpose  : 
169 //=======================================================================
170 /*!
171  * Auxilary function for filling myNLinkNodeMap
172  */
173 void SMESH_MesherHelper::AddNLinkNode(const SMDS_MeshNode* n1,
174                                      const SMDS_MeshNode* n2,
175                                      const SMDS_MeshNode* n12)
176 {
177   NLink link( n1, n2 );
178   if ( n1 > n2 ) link = NLink( n2, n1 );
179   // add new record to map
180   myNLinkNodeMap.insert( make_pair(link,n12));
181 }
182
183 //=======================================================================
184 /*!
185  * \brief Select UV on either of 2 pcurves of a seam edge, closest to the given UV
186  * \param uv1 - UV on the seam
187  * \param uv2 - UV within a face
188  * \retval gp_Pnt2d - selected UV
189  */
190 //=======================================================================
191
192 gp_Pnt2d SMESH_MesherHelper::GetUVOnSeam( const gp_Pnt2d& uv1, const gp_Pnt2d& uv2 ) const
193 {
194   double p1 = uv1.Coord( myParIndex );
195   double p2 = uv2.Coord( myParIndex );
196   double p3 = ( Abs( p1 - myPar1 ) < Abs( p1 - myPar2 )) ? myPar2 : myPar1;
197   if ( Abs( p2 - p1 ) > Abs( p2 - p3 ))
198     p1 = p3;
199   gp_Pnt2d result = uv1;
200   result.SetCoord( myParIndex, p1 );
201   return result;
202 }
203
204 //=======================================================================
205 /*!
206  * \brief Return node UV on face
207  * \param F - the face
208  * \param n - the node
209  * \param n2 - a medium node will be placed between n and n2
210  * \retval gp_XY - resulting UV
211  * 
212  * Auxilary function called form GetMediumNode()
213  */
214 //=======================================================================
215
216 gp_XY SMESH_MesherHelper::GetNodeUV(const TopoDS_Face&   F,
217                                     const SMDS_MeshNode* n,
218                                     const SMDS_MeshNode* n2)
219 {
220   gp_Pnt2d uv;
221   const SMDS_PositionPtr Pos = n->GetPosition();
222   if(Pos->GetTypeOfPosition()==SMDS_TOP_FACE) {
223     // node has position on face
224     const SMDS_FacePosition* fpos =
225       static_cast<const SMDS_FacePosition*>(n->GetPosition().get());
226     uv = gp_Pnt2d(fpos->GetUParameter(),fpos->GetVParameter());
227   }
228   else if(Pos->GetTypeOfPosition()==SMDS_TOP_EDGE) {
229     // node has position on edge => it is needed to find
230     // corresponding edge from face, get pcurve for this
231     // edge and recieve value from this pcurve
232     const SMDS_EdgePosition* epos =
233       static_cast<const SMDS_EdgePosition*>(n->GetPosition().get());
234     SMESHDS_Mesh* meshDS = GetMesh()->GetMeshDS();
235     int edgeID = Pos->GetShapeId();
236     TopoDS_Edge E = TopoDS::Edge(meshDS->IndexToShape(edgeID));
237     double f, l;
238     TopLoc_Location loc;
239     Handle(Geom2d_Curve) C2d = BRep_Tool::CurveOnSurface(E, F, f, l);
240     uv = C2d->Value( epos->GetUParameter() );
241     // for a node on a seam edge select one of UVs on 2 pcurves
242     if ( n2 && mySeamShapeIds.find( edgeID ) != mySeamShapeIds.end() )
243       uv = GetUVOnSeam( uv, GetNodeUV( F, n2, 0 ));
244   }
245   else if(Pos->GetTypeOfPosition()==SMDS_TOP_VERTEX) {
246     SMESHDS_Mesh * meshDS = GetMesh()->GetMeshDS();
247     int vertexID = n->GetPosition()->GetShapeId();
248     const TopoDS_Vertex& V = TopoDS::Vertex(meshDS->IndexToShape(vertexID));
249     uv = BRep_Tool::Parameters( V, F );
250     if ( n2 && mySeamShapeIds.find( vertexID ) != mySeamShapeIds.end() )
251       uv = GetUVOnSeam( uv, GetNodeUV( F, n2, 0 ));
252   }
253   return uv.XY();
254 }
255
256 //=======================================================================
257 /*!
258  * \brief Return node U on edge
259  * \param E - the Edge
260  * \param n - the node
261  * \retval double - resulting U
262  * 
263  * Auxilary function called form GetMediumNode()
264  */
265 //=======================================================================
266
267 double SMESH_MesherHelper::GetNodeU(const TopoDS_Edge&   E,
268                                     const SMDS_MeshNode* n)
269 {
270   double param = 0;
271   const SMDS_PositionPtr Pos = n->GetPosition();
272   if(Pos->GetTypeOfPosition()==SMDS_TOP_EDGE) {
273     const SMDS_EdgePosition* epos =
274       static_cast<const SMDS_EdgePosition*>(n->GetPosition().get());
275     param =  epos->GetUParameter();
276   }
277   else if(Pos->GetTypeOfPosition()==SMDS_TOP_VERTEX) {
278     SMESHDS_Mesh * meshDS = GetMesh()->GetMeshDS();
279     int vertexID = n->GetPosition()->GetShapeId();
280     const TopoDS_Vertex& V = TopoDS::Vertex(meshDS->IndexToShape(vertexID));
281     param =  BRep_Tool::Parameter( V, E );
282   }
283   return param;
284 }
285
286 //=======================================================================
287 //function : GetMediumNode
288 //purpose  : 
289 //=======================================================================
290 /*!
291  * Special function for search or creation medium node
292  */
293 const SMDS_MeshNode* SMESH_MesherHelper::GetMediumNode(const SMDS_MeshNode* n1,
294                                                        const SMDS_MeshNode* n2,
295                                                        bool force3d)
296 {
297   TopAbs_ShapeEnum shapeType = myShape.IsNull() ? TopAbs_SHAPE : myShape.ShapeType();
298
299   NLink link(( n1 < n2 ? n1 : n2 ), ( n1 < n2 ? n2 : n1 ));
300   ItNLinkNode itLN = myNLinkNodeMap.find( link );
301   if ( itLN != myNLinkNodeMap.end() ) {
302     return (*itLN).second;
303   }
304   else {
305     // create medium node
306     SMDS_MeshNode* n12;
307     SMESHDS_Mesh* meshDS = GetMesh()->GetMeshDS();
308     int faceID = -1, edgeID = -1;
309     const SMDS_PositionPtr Pos1 = n1->GetPosition();
310     const SMDS_PositionPtr Pos2 = n2->GetPosition();
311   
312     if( myShape.IsNull() )
313     {
314       if( Pos1->GetTypeOfPosition()==SMDS_TOP_FACE ) {
315         faceID = Pos1->GetShapeId();
316       }
317       else if( Pos2->GetTypeOfPosition()==SMDS_TOP_FACE ) {
318         faceID = Pos2->GetShapeId();
319       }
320
321       if( Pos1->GetTypeOfPosition()==SMDS_TOP_EDGE ) {
322         edgeID = Pos1->GetShapeId();
323       }
324       if( Pos2->GetTypeOfPosition()==SMDS_TOP_EDGE ) {
325         edgeID = Pos2->GetShapeId();
326       }
327     }
328
329     if(!force3d) {
330       // we try to create medium node using UV parameters of
331       // nodes, else - medium between corresponding 3d points
332       if(faceID>-1 || shapeType == TopAbs_FACE) {
333         // obtaining a face and 2d points for nodes
334         TopoDS_Face F;
335         if( myShape.IsNull() )
336           F = TopoDS::Face(meshDS->IndexToShape(faceID));
337         else {
338           F = TopoDS::Face(myShape);
339           faceID = myShapeID;
340         }
341
342         gp_XY p1 = GetNodeUV(F,n1,n2);
343         gp_XY p2 = GetNodeUV(F,n2,n1);
344
345         //checking if surface is periodic
346         Handle(Geom_Surface) S = BRep_Tool::Surface(F);
347         Standard_Real UF,UL,VF,VL;
348         S->Bounds(UF,UL,VF,VL);
349
350         Standard_Real u,v;
351         Standard_Boolean isUPeriodic = S->IsUPeriodic();
352         if(isUPeriodic) {
353           Standard_Real UPeriod = S->UPeriod();
354           Standard_Real p2x = p2.X()+ShapeAnalysis::AdjustByPeriod(p2.X(),p1.X(),UPeriod);
355           Standard_Real pmid = (p1.X()+p2x)/2.;
356           u = pmid+ShapeAnalysis::AdjustToPeriod(pmid,UF,UL);
357         }
358         else 
359           u= (p1.X()+p2.X())/2.;
360
361         Standard_Boolean isVPeriodic = S->IsVPeriodic();
362         if(isVPeriodic) {
363           Standard_Real VPeriod = S->VPeriod();
364           Standard_Real p2y = p2.Y()+ShapeAnalysis::AdjustByPeriod(p2.Y(),p1.Y(),VPeriod);
365           Standard_Real pmid = (p1.Y()+p2y)/2.;
366           v = pmid+ShapeAnalysis::AdjustToPeriod(pmid,VF,VL);
367         }
368         else
369           v = (p1.Y()+p2.Y())/2.;
370
371         gp_Pnt P = S->Value(u, v);
372         n12 = meshDS->AddNode(P.X(), P.Y(), P.Z());
373         meshDS->SetNodeOnFace(n12, faceID, u, v);
374         myNLinkNodeMap.insert(NLinkNodeMap::value_type(link,n12));
375         return n12;
376       }
377       if (edgeID>-1 || shapeType == TopAbs_EDGE) {
378
379         TopoDS_Edge E;
380         if( myShape.IsNull() )
381           E = TopoDS::Edge(meshDS->IndexToShape(edgeID));
382         else {
383           E = TopoDS::Edge(myShape);
384           edgeID = myShapeID;
385         }
386
387         double p1 = GetNodeU(E,n1);
388         double p2 = GetNodeU(E,n2);
389
390         double f,l;
391         Handle(Geom_Curve) C = BRep_Tool::Curve(E, f, l);
392         if(!C.IsNull()) {
393
394           Standard_Boolean isPeriodic = C->IsPeriodic();
395           double u;
396           if(isPeriodic) {
397             Standard_Real Period = C->Period();
398             Standard_Real p = p2+ShapeAnalysis::AdjustByPeriod(p2,p1,Period);
399             Standard_Real pmid = (p1+p)/2.;
400             u = pmid+ShapeAnalysis::AdjustToPeriod(pmid,C->FirstParameter(),C->LastParameter());
401           }
402           else
403             u = (p1+p2)/2.;
404
405           gp_Pnt P = C->Value( u );
406           n12 = meshDS->AddNode(P.X(), P.Y(), P.Z());
407           meshDS->SetNodeOnEdge(n12, edgeID, u);
408           myNLinkNodeMap.insert(NLinkNodeMap::value_type(link,n12));
409           return n12;
410         }
411       }
412     }
413     // 3d variant
414     double x = ( n1->X() + n2->X() )/2.;
415     double y = ( n1->Y() + n2->Y() )/2.;
416     double z = ( n1->Z() + n2->Z() )/2.;
417     n12 = meshDS->AddNode(x,y,z);
418     if(edgeID>-1)
419         meshDS->SetNodeOnEdge(n12, edgeID);
420     else if(faceID>-1)
421         meshDS->SetNodeOnFace(n12, faceID);
422     else
423       meshDS->SetNodeInVolume(n12, myShapeID);
424     myNLinkNodeMap.insert(NLinkNodeMap::value_type(link,n12));
425     return n12;
426   }
427 }
428
429 //=======================================================================
430 //function : AddQuadraticEdge
431 //purpose  : 
432 //=======================================================================
433 /**
434  * Special function for creation quadratic edge
435  */
436 SMDS_QuadraticEdge* SMESH_MesherHelper::AddQuadraticEdge(const SMDS_MeshNode* n1,
437                                                          const SMDS_MeshNode* n2,
438                                                          const int id,
439                                                          const bool force3d)
440 {
441   SMESHDS_Mesh * meshDS = GetMesh()->GetMeshDS();
442   
443   const SMDS_MeshNode* n12 = GetMediumNode(n1,n2,force3d);
444   
445   myCreateQuadratic = true;
446
447   if(id)
448     return  (SMDS_QuadraticEdge*)(meshDS->AddEdgeWithID(n1, n2, n12, id));
449   else
450     return  (SMDS_QuadraticEdge*)(meshDS->AddEdge(n1, n2, n12));
451 }
452
453 //=======================================================================
454 //function : AddFace
455 //purpose  : 
456 //=======================================================================
457 /*!
458  * Special function for creation quadratic triangle
459  */
460 SMDS_MeshFace* SMESH_MesherHelper::AddFace(const SMDS_MeshNode* n1,
461                                            const SMDS_MeshNode* n2,
462                                            const SMDS_MeshNode* n3,
463                                            const int id,
464                                            const bool force3d)
465 {
466   SMESHDS_Mesh * meshDS = GetMesh()->GetMeshDS();
467   if(!myCreateQuadratic) {
468     if(id)
469       return  meshDS->AddFaceWithID(n1, n2, n3, id);
470     else
471       return  meshDS->AddFace(n1, n2, n3);
472   }
473
474   const SMDS_MeshNode* n12 = GetMediumNode(n1,n2,force3d);
475   const SMDS_MeshNode* n23 = GetMediumNode(n2,n3,force3d);
476   const SMDS_MeshNode* n31 = GetMediumNode(n3,n1,force3d);
477
478   if(id)
479     return  meshDS->AddFaceWithID(n1, n2, n3, n12, n23, n31, id);
480   else
481     return  meshDS->AddFace(n1, n2, n3, n12, n23, n31);
482 }
483
484
485 //=======================================================================
486 //function : AddFace
487 //purpose  : 
488 //=======================================================================
489 /*!
490  * Special function for creation quadratic quadrangle
491  */
492 SMDS_MeshFace* SMESH_MesherHelper::AddFace(const SMDS_MeshNode* n1,
493                                            const SMDS_MeshNode* n2,
494                                            const SMDS_MeshNode* n3,
495                                            const SMDS_MeshNode* n4,
496                                            const int id,
497                                            const bool force3d)
498 {
499   SMESHDS_Mesh * meshDS = GetMesh()->GetMeshDS();
500   if(!myCreateQuadratic) {
501     if(id)
502       return  meshDS->AddFaceWithID(n1, n2, n3, n4, id);
503     else
504       return  meshDS->AddFace(n1, n2, n3, n4);
505   }
506
507   const SMDS_MeshNode* n12 = GetMediumNode(n1,n2,force3d);
508   const SMDS_MeshNode* n23 = GetMediumNode(n2,n3,force3d);
509   const SMDS_MeshNode* n34 = GetMediumNode(n3,n4,force3d);
510   const SMDS_MeshNode* n41 = GetMediumNode(n4,n1,force3d);
511
512   if(id)
513     return  meshDS->AddFaceWithID(n1, n2, n3, n4, n12, n23, n34, n41, id);
514   else
515     return  meshDS->AddFace(n1, n2, n3, n4, n12, n23, n34, n41);
516 }
517
518
519 //=======================================================================
520 //function : AddVolume
521 //purpose  : 
522 //=======================================================================
523 /*!
524  * Special function for creation quadratic volume
525  */
526 SMDS_MeshVolume* SMESH_MesherHelper::AddVolume(const SMDS_MeshNode* n1,
527                                                const SMDS_MeshNode* n2,
528                                                const SMDS_MeshNode* n3,
529                                                const SMDS_MeshNode* n4,
530                                                const SMDS_MeshNode* n5,
531                                                const SMDS_MeshNode* n6,
532                                                const int id,
533                                                const bool force3d)
534 {
535   SMESHDS_Mesh * meshDS = GetMesh()->GetMeshDS();
536   if(!myCreateQuadratic) {
537     if(id)
538       return meshDS->AddVolumeWithID(n1, n2, n3, n4, n5, n6, id);
539     else
540       return meshDS->AddVolume(n1, n2, n3, n4, n5, n6);
541   }
542
543   const SMDS_MeshNode* n12 = GetMediumNode(n1,n2,force3d);
544   const SMDS_MeshNode* n23 = GetMediumNode(n2,n3,force3d);
545   const SMDS_MeshNode* n31 = GetMediumNode(n3,n1,force3d);
546
547   const SMDS_MeshNode* n45 = GetMediumNode(n4,n5,force3d);
548   const SMDS_MeshNode* n56 = GetMediumNode(n5,n6,force3d);
549   const SMDS_MeshNode* n64 = GetMediumNode(n6,n4,force3d);
550
551   const SMDS_MeshNode* n14 = GetMediumNode(n1,n4,force3d);
552   const SMDS_MeshNode* n25 = GetMediumNode(n2,n5,force3d);
553   const SMDS_MeshNode* n36 = GetMediumNode(n3,n6,force3d);
554
555   if(id)
556     return meshDS->AddVolumeWithID(n1, n2, n3, n4, n5, n6, 
557                                    n12, n23, n31, n45, n56, n64, n14, n25, n36, id);
558   else
559     return meshDS->AddVolume(n1, n2, n3, n4, n5, n6,
560                              n12, n23, n31, n45, n56, n64, n14, n25, n36);
561 }
562
563
564 //=======================================================================
565 //function : AddVolume
566 //purpose  : 
567 //=======================================================================
568 /*!
569  * Special function for creation quadratic volume
570  */
571 SMDS_MeshVolume* SMESH_MesherHelper::AddVolume(const SMDS_MeshNode* n1,
572                                                const SMDS_MeshNode* n2,
573                                                const SMDS_MeshNode* n3,
574                                                const SMDS_MeshNode* n4,
575                                                const int id, 
576                                                const bool force3d)
577 {
578   SMESHDS_Mesh * meshDS = GetMesh()->GetMeshDS();
579   if(!myCreateQuadratic) {
580     if(id)
581       return meshDS->AddVolumeWithID(n1, n2, n3, n4, id);
582     else
583       return meshDS->AddVolume(n1, n2, n3, n4);
584   }
585
586   const SMDS_MeshNode* n12 = GetMediumNode(n1,n2,force3d);
587   const SMDS_MeshNode* n23 = GetMediumNode(n2,n3,force3d);
588   const SMDS_MeshNode* n31 = GetMediumNode(n3,n1,force3d);
589
590   const SMDS_MeshNode* n14 = GetMediumNode(n1,n4,force3d);
591   const SMDS_MeshNode* n24 = GetMediumNode(n2,n4,force3d);
592   const SMDS_MeshNode* n34 = GetMediumNode(n3,n4,force3d);
593
594   if(id)
595     return meshDS->AddVolumeWithID(n1, n2, n3, n4, n12, n23, n31, n14, n24, n34, id);
596   else
597     return meshDS->AddVolume(n1, n2, n3, n4, n12, n23, n31, n14, n24, n34);
598 }
599
600
601 //=======================================================================
602 //function : AddVolume
603 //purpose  : 
604 //=======================================================================
605 /*!
606  * Special function for creation quadratic volume
607  */
608 SMDS_MeshVolume* SMESH_MesherHelper::AddVolume(const SMDS_MeshNode* n1,
609                                                const SMDS_MeshNode* n2,
610                                                const SMDS_MeshNode* n3,
611                                                const SMDS_MeshNode* n4,
612                                                const SMDS_MeshNode* n5,
613                                                const SMDS_MeshNode* n6,
614                                                const SMDS_MeshNode* n7,
615                                                const SMDS_MeshNode* n8,
616                                                const int id,
617                                                const bool force3d)
618 {
619   SMESHDS_Mesh * meshDS = GetMesh()->GetMeshDS();
620   if(!myCreateQuadratic) {
621     if(id)
622       return meshDS->AddVolumeWithID(n1, n2, n3, n4, n5, n6, n7, n8, id);
623     else
624       return meshDS->AddVolume(n1, n2, n3, n4, n5, n6, n7, n8);
625   }
626
627   const SMDS_MeshNode* n12 = GetMediumNode(n1,n2,force3d);
628   const SMDS_MeshNode* n23 = GetMediumNode(n2,n3,force3d);
629   const SMDS_MeshNode* n34 = GetMediumNode(n3,n4,force3d);
630   const SMDS_MeshNode* n41 = GetMediumNode(n4,n1,force3d);
631
632   const SMDS_MeshNode* n56 = GetMediumNode(n5,n6,force3d);
633   const SMDS_MeshNode* n67 = GetMediumNode(n6,n7,force3d);
634   const SMDS_MeshNode* n78 = GetMediumNode(n7,n8,force3d);
635   const SMDS_MeshNode* n85 = GetMediumNode(n8,n5,force3d);
636
637   const SMDS_MeshNode* n15 = GetMediumNode(n1,n5,force3d);
638   const SMDS_MeshNode* n26 = GetMediumNode(n2,n6,force3d);
639   const SMDS_MeshNode* n37 = GetMediumNode(n3,n7,force3d);
640   const SMDS_MeshNode* n48 = GetMediumNode(n4,n8,force3d);
641
642   if(id)
643     return meshDS->AddVolumeWithID(n1, n2, n3, n4, n5, n6, n7, n8,
644                                    n12, n23, n34, n41, n56, n67,
645                                    n78, n85, n15, n26, n37, n48, id);
646   else
647     return meshDS->AddVolume(n1, n2, n3, n4, n5, n6, n7, n8,
648                              n12, n23, n34, n41, n56, n67,
649                              n78, n85, n15, n26, n37, n48);
650 }
651
652