]> SALOME platform Git repositories - modules/smesh.git/blob - src/SMDS/SMDS_VolumeTool.cxx
Salome HOME
Improve SMDS: extract ElemIterator into a separate header
[modules/smesh.git] / src / SMDS / SMDS_VolumeTool.cxx
1 // File      : SMDS_VolumeTool.cxx
2 // Created   : Tue Jul 13 12:22:13 2004
3 // Author    : Edward AGAPOV (eap)
4 // Copyright : Open CASCADE
5
6 #ifdef _MSC_VER
7 #pragma warning(disable:4786)
8 #endif
9
10 #include "SMDS_VolumeTool.hxx"
11
12 #include "SMDS_MeshElement.hxx"
13 #include "SMDS_MeshNode.hxx"
14 #include <map>
15 #include <float.h>
16 #include <math.h>
17
18 using namespace std;
19
20 /*
21 //           N3
22 //           +
23 //          /|\
24 //         / | \
25 //        /  |  \
26 //    N0 +---|---+ N2                TETRAHEDRON
27 //       \   |   /
28 //        \  |  /
29 //         \ | /
30 //          \|/
31 //           +
32 //           N1
33 */
34 static int Tetra_F [4][4] = { // FORWARD == REVERSED EXTERNAL
35   { 0, 1, 2, 0 },             // Bottom face has an internal normal, other - external
36   { 0, 1, 3, 0 },
37   { 1, 2, 3, 1 },
38   { 0, 3, 2, 0 }}; 
39 static int Tetra_R [4][4] = { // REVERSED == FORWARD EXTERNAL
40   { 0, 2, 1, 0 },              // All faces have  external normals
41   { 0, 1, 3, 0 },
42   { 1, 2, 3, 1 },
43   { 0, 3, 2, 0 }}; 
44 static int Tetra_nbN [] = { 3, 3, 3, 3 };
45
46 /*   
47 //            + N4
48 //           /|\
49 //          / | \
50 //         /  |  \
51 //        /   |   \
52 //    N3 +---------+ N5
53 //       |    |    |
54 //       |    + N1 |
55 //       |   / \   |                PENTAHEDRON
56 //       |  /   \  |
57 //       | /     \ |
58 //       |/       \|
59 //    N0 +---------+ N2
60 */
61 static int Penta_F [5][5] = { // FORWARD
62   { 0, 1, 2, 0, 0 },          // Top face has an internal normal, other - external
63   { 3, 4, 5, 3, 3 },          // 0 is bottom, 1 is top face
64   { 0, 2, 5, 3, 0 },
65   { 1, 2, 5, 4, 1 },
66   { 1, 0, 3, 4, 1 }}; 
67 static int Penta_R [5][5] = { // REVERSED
68   { 0, 2, 1, 0, 0 },          // Bottom face has an internal normal, other - external
69   { 3, 5, 4, 3, 3 },          // 0 is bottom, 1 is top face
70   { 0, 2, 5, 3, 0 },
71   { 1, 2, 5, 4, 1 },
72   { 1, 0, 3, 4, 1 }}; 
73 static int Penta_FE [5][5] = { // EXTERNAL
74   { 0, 1, 2, 0, 0 },
75   { 3, 5, 4, 3, 3 },
76   { 0, 2, 5, 3, 0 },
77   { 1, 2, 5, 4, 1 },
78   { 1, 0, 3, 4, 1 }}; 
79 static int Penta_RE [5][5] = { // REVERSED EXTERNAL
80   { 0, 0, 2, 1, 0 },
81   { 3, 3, 4, 5, 3 },
82   { 0, 2, 5, 3, 0 },
83   { 1, 2, 5, 4, 1 },
84   { 1, 0, 3, 4, 1 }}; 
85 static int Penta_nbN [] = { 3, 3, 4, 4, 4 };
86
87 /*
88 //         N7+----------+N6
89 //          /|         /|
90 //         / |        / |
91 //        /  |       /  |
92 //     N4+----------+N5 |
93 //       |   |      |   |           HEXAHEDRON
94 //       |   |      |   |
95 //       |   |      |   |
96 //       | N3+------|---+N2
97 //       |  /       |  /
98 //       | /        | /
99 //       |/         |/
100 //     N0+----------+N1
101 */
102 static int Hexa_F [6][5] = { // FORWARD
103   { 0, 1, 2, 3, 0 },         // opposite faces are neighbouring,
104   { 4, 5, 6, 7, 4 },         // even face normal is internal, odd - external
105   { 1, 0, 4, 5, 1 },         // same index nodes of opposite faces are linked
106   { 2, 3, 7, 6, 2 }, 
107   { 0, 3, 7, 4, 0 }, 
108   { 1, 2, 6, 5, 1 }}; 
109 static int Hexa_R [6][5] = { // REVERSED
110   { 0, 3, 2, 1, 0 },         // opposite faces are neighbouring,
111   { 4, 7, 6, 5, 4 },         // even face normal is external, odd - internal
112   { 1, 5, 4, 0, 1 },         // same index nodes of opposite faces are linked
113   { 2, 6, 7, 3, 2 }, 
114   { 0, 4, 7, 3, 0 }, 
115   { 1, 5, 6, 2, 1 }}; 
116 static int Hexa_FE [6][5] = { // EXTERNAL
117   { 0, 3, 2, 1, 0 },         // opposite faces are neighbouring,
118   { 4, 5, 6, 7, 4 },         // all face normals are external,
119   { 0, 1, 5, 4, 0 },         // links in opposite faces: 0-0, 1-3, 2-2, 3-1
120   { 3, 7, 6, 2, 3 }, 
121   { 1, 2, 6, 5, 1 }, 
122   { 0, 4, 7, 3, 0 }};
123 static int Hexa_RE [6][5] = { // REVERSED EXTERNAL
124   { 0, 1, 2, 3, 0 },         // opposite faces are neighbouring,
125   { 4, 7, 6, 5, 4 },         // all face normals are external,
126   { 0, 1, 5, 4, 0 },         // links in opposite faces: 0-0, 1-3, 2-2, 3-1
127   { 3, 7, 6, 2, 3 }, 
128   { 1, 2, 6, 5, 1 }, 
129   { 0, 4, 7, 3, 0 }};
130 static int Hexa_nbN [] = { 4, 4, 4, 4, 4, 4 };
131
132 // ========================================================
133 // to perform some calculations without linkage to CASCADE
134 // ========================================================
135 struct XYZ {
136   double x;
137   double y;
138   double z;
139   XYZ()                               { x = 0; y = 0; z = 0; }
140   XYZ( double X, double Y, double Z ) { x = X; y = Y; z = Z; }
141   XYZ( const XYZ& other )             { x = other.x; y = other.y; z = other.z; }
142   XYZ( const SMDS_MeshNode* n )       { x = n->X(); y = n->Y(); z = n->Z(); }
143   XYZ operator-( const XYZ& other );
144   XYZ Crossed( const XYZ& other );
145   double Dot( const XYZ& other );
146   double Magnitude();
147 };
148 XYZ XYZ::operator-( const XYZ& Right ) {
149   return XYZ(x - Right.x, y - Right.y, z - Right.z);
150 }
151 XYZ XYZ::Crossed( const XYZ& Right ) {
152   return XYZ (y * Right.z - z * Right.y,
153               z * Right.x - x * Right.z,
154               x * Right.y - y * Right.x);
155 }
156 double XYZ::Dot( const XYZ& Other ) {
157   return(x * Other.x + y * Other.y + z * Other.z);
158 }
159 double XYZ::Magnitude() {
160   return sqrt (x * x + y * y + z * z);
161 }
162
163 //=======================================================================
164 //function : SMDS_VolumeTool
165 //purpose  : 
166 //=======================================================================
167
168 SMDS_VolumeTool::SMDS_VolumeTool ()
169      : myVolume( 0 ),
170        myVolForward( true ),
171        myNbFaces( 0 ),
172        myVolumeNbNodes( 0 ),
173        myForwardFaces( false ),
174        myExternalFaces( false )
175 {
176 }
177 //=======================================================================
178 //function : SMDS_VolumeTool
179 //purpose  : 
180 //=======================================================================
181
182 SMDS_VolumeTool::SMDS_VolumeTool (const SMDS_MeshElement* theVolume)
183      : myForwardFaces( false ),
184        myExternalFaces( false )
185 {
186   Set( theVolume );
187 }
188
189 //=======================================================================
190 //function : SMDS_VolumeTool
191 //purpose  : 
192 //=======================================================================
193
194 SMDS_VolumeTool::~SMDS_VolumeTool()
195 {
196 }
197
198 //=======================================================================
199 //function : SetVolume
200 //purpose  : Set volume to iterate on
201 //=======================================================================
202
203 bool SMDS_VolumeTool::Set (const SMDS_MeshElement* theVolume)
204 {
205   myVolume = 0;
206   myVolForward = true;
207   myCurFace = -1;
208   myVolumeNbNodes = 0;
209   myNbFaces = 0;
210   if ( theVolume && theVolume->GetType() == SMDSAbs_Volume )
211   {
212     myVolumeNbNodes = theVolume->NbNodes();
213     switch ( myVolumeNbNodes ) {
214     case 4:
215     case 6:
216     case 8:
217       {
218       myVolume = theVolume;
219       myNbFaces = theVolume->NbFaces();
220
221       // set volume nodes
222       int iNode = 0;
223       SMDS_ElemIteratorPtr nodeIt = myVolume->nodesIterator();
224       while ( nodeIt->more() )
225         myVolumeNodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
226
227       // nb nodes in each face
228       if ( myVolumeNbNodes == 4 )
229         myFaceNbNodes = Tetra_nbN;
230       else if ( myVolumeNbNodes == 6 )
231         myFaceNbNodes = Penta_nbN;
232       else
233         myFaceNbNodes = Hexa_nbN;
234
235       // define volume orientation
236       XYZ botNormal;
237       GetFaceNormal( 0, botNormal.x, botNormal.y, botNormal.z );
238       const SMDS_MeshNode* topNode = myVolumeNodes[ myVolumeNbNodes - 1 ];
239       const SMDS_MeshNode* botNode = myVolumeNodes[ 0 ];
240       XYZ upDir (topNode->X() - botNode->X(),
241                  topNode->Y() - botNode->Y(),
242                  topNode->Z() - botNode->Z() );
243       bool diffDir = ( botNormal.Dot( upDir ) < 0 );
244       myVolForward = ( myVolumeNbNodes == 6 ? diffDir : !diffDir );
245       break;
246     }
247     default: myVolume = 0;
248     }
249   }
250   return ( myVolume != 0 );
251 }
252
253 //=======================================================================
254 //function : GetInverseNodes
255 //purpose  : Return nodes vector of an inverse volume
256 //=======================================================================
257
258 #define SWAP_NODES(nodes,i1,i2)           \
259 {                                         \
260   const SMDS_MeshNode* tmp = nodes[ i1 ]; \
261   nodes[ i1 ] = nodes[ i2 ];              \
262   nodes[ i2 ] = tmp;                      \
263 }
264 void SMDS_VolumeTool::Inverse ()
265 {
266   if ( !myVolume ) return;
267
268   myVolForward = !myVolForward;
269   myCurFace = -1;
270
271   // inverse top and bottom faces
272   switch ( myVolumeNbNodes ) {
273   case 4:
274     SWAP_NODES( myVolumeNodes, 1, 2 );
275     break;
276   case 6:
277     SWAP_NODES( myVolumeNodes, 1, 2 );
278     SWAP_NODES( myVolumeNodes, 4, 5 );
279     break;
280   case 8:
281     SWAP_NODES( myVolumeNodes, 1, 3 );
282     SWAP_NODES( myVolumeNodes, 5, 7 );
283     break;
284   default:;
285   }
286 }
287
288 //=======================================================================
289 //function : GetSize
290 //purpose  : Return element volume
291 //=======================================================================
292
293 double SMDS_VolumeTool::GetSize() const
294 {
295   return 0;
296 }
297
298 //=======================================================================
299 //function : GetBaryCenter
300 //purpose  : 
301 //=======================================================================
302
303 bool SMDS_VolumeTool::GetBaryCenter(double & X, double & Y, double & Z) const
304 {
305   X = Y = Z = 0.;
306   if ( !myVolume )
307     return false;
308
309   for ( int i = 0; i < myVolumeNbNodes; i++ ) {
310     X += myVolumeNodes[ i ]->X();
311     Y += myVolumeNodes[ i ]->Y();
312     Z += myVolumeNodes[ i ]->Z();
313   }
314   X /= myVolumeNbNodes;
315   Y /= myVolumeNbNodes;
316   Z /= myVolumeNbNodes;
317
318   return true;
319 }
320
321 //=======================================================================
322 //function : SetForwardOrientation
323 //purpose  : Node order will be as for forward orientation
324 //=======================================================================
325
326 void SMDS_VolumeTool::SetForwardOrientation ()
327 {
328   myForwardFaces = true;
329 }
330
331 //=======================================================================
332 //function : SetExternalNormal
333 //purpose  : Node order will be so that faces normals are external
334 //=======================================================================
335
336 void SMDS_VolumeTool::SetExternalNormal ()
337 {
338   myExternalFaces = true;
339 }
340
341 //=======================================================================
342 //function : NbFaceNodes
343 //purpose  : Return number of nodes in the array of face nodes
344 //=======================================================================
345
346 int SMDS_VolumeTool::NbFaceNodes( int faceIndex )
347 {
348   if ( !setFace( faceIndex ))
349     return 0;
350   return myFaceNbNodes[ faceIndex ];
351 }
352
353 //=======================================================================
354 //function : GetFaceNodes
355 //purpose  : Return pointer to the array of face nodes.
356 //           To comfort link iteration, the array
357 //           length == NbFaceNodes( faceIndex ) + 1 and
358 //           the last node == the first one.
359 //=======================================================================
360
361 const SMDS_MeshNode** SMDS_VolumeTool::GetFaceNodes( int faceIndex )
362 {
363   if ( !setFace( faceIndex ))
364     return 0;
365   return myFaceNodes;
366 }
367
368 //=======================================================================
369 //function : GetFaceNodesIndices
370 //purpose  : Return pointer to the array of face nodes indices
371 //           To comfort link iteration, the array
372 //           length == NbFaceNodes( faceIndex ) + 1 and
373 //           the last node index == the first one.
374 //=======================================================================
375
376 const int* SMDS_VolumeTool::GetFaceNodesIndices( int faceIndex )
377 {
378   if ( !setFace( faceIndex ))
379     return 0;
380   return myFaceNodeIndices;
381 }
382
383 //=======================================================================
384 //function : GetFaceNodes
385 //purpose  : Return a set of face nodes.
386 //=======================================================================
387
388 bool SMDS_VolumeTool::GetFaceNodes (int faceIndex,
389                                     std::set<const SMDS_MeshNode*>& theFaceNodes )
390 {
391   if ( !setFace( faceIndex ))
392     return false;
393
394   theFaceNodes.clear();
395   int iNode, nbNode = myFaceNbNodes[ faceIndex ];
396   for ( iNode = 0; iNode < nbNode; iNode++ )
397     theFaceNodes.insert( myFaceNodes[ iNode ]);
398   
399   return true;
400 }
401
402 //=======================================================================
403 //function : IsFaceExternal
404 //purpose  : Check normal orientation of a returned face
405 //=======================================================================
406
407 bool SMDS_VolumeTool::IsFaceExternal( int faceIndex )
408 {
409   if ( myExternalFaces || !myVolume )
410     return true;
411
412   bool reversed = ( !myForwardFaces && !myVolForward );
413   switch ( myVolumeNbNodes ) {
414   case 4:
415     // only the bottom of a forward tetrahedron can be internal
416     return ( reversed || faceIndex != 0 );
417   case 6:
418     // in a forward pentahedron, the top is internal, in a reversed one - bottom
419     return ( reversed ? faceIndex != 0 : faceIndex != 1 );
420   case 8: {
421     // in a forward hexahedron, odd face normal is external, else vice versa
422     bool odd = (faceIndex % 2 != 0);
423     return ( reversed ? !odd : odd );
424   }
425   default:;
426   }
427   return false;
428 }
429
430 //=======================================================================
431 //function : GetFaceNormal
432 //purpose  : Return a normal to a face
433 //=======================================================================
434
435 bool SMDS_VolumeTool::GetFaceNormal (int faceIndex, double & X, double & Y, double & Z)
436 {
437   if ( !setFace( faceIndex ))
438     return false;
439
440   XYZ p1 ( myFaceNodes[0] );
441   XYZ p2 ( myFaceNodes[1] );
442   XYZ p3 ( myFaceNodes[2] );
443   XYZ aVec12( p2 - p1 );
444   XYZ aVec13( p3 - p1 );
445   XYZ cross = aVec12.Crossed( aVec13 );
446
447   double size = cross.Magnitude();
448   if ( size <= DBL_MIN )
449     return false;
450
451   X = cross.x / size;
452   Y = cross.y / size;
453   Z = cross.z / size;
454
455   return true;
456 }
457
458
459 //=======================================================================
460 //function : GetFaceArea
461 //purpose  : Return face area
462 //=======================================================================
463
464 double SMDS_VolumeTool::GetFaceArea( int faceIndex )
465 {
466   if ( !setFace( faceIndex ))
467     return 0;
468
469   XYZ p1 ( myFaceNodes[0] );
470   XYZ p2 ( myFaceNodes[1] );
471   XYZ p3 ( myFaceNodes[2] );
472   XYZ aVec12( p2 - p1 );
473   XYZ aVec13( p3 - p1 );
474   double area = aVec12.Crossed( aVec13 ).Magnitude() * 0.5;
475
476   if ( myFaceNbNodes[ faceIndex ] == 4 ) {
477     XYZ p4 ( myFaceNodes[3] );
478     XYZ aVec14( p4 - p1 );
479     area += aVec14.Crossed( aVec13 ).Magnitude() * 0.5;
480   }
481   return area;
482 }
483
484 //=======================================================================
485 //function : GetOppFaceIndex
486 //purpose  : Return index of the opposite face if it exists, else -1.
487 //=======================================================================
488
489 int SMDS_VolumeTool::GetOppFaceIndex( int faceIndex ) const
490 {
491   int ind = -1;
492   if ( faceIndex >= 0 && faceIndex < NbFaces() ) {
493     switch ( myVolumeNbNodes ) {
494     case 6:
495       if ( faceIndex == 0 || faceIndex == 1 )
496         ind = 1 - faceIndex;
497       break;
498     case 8:
499       ind = faceIndex + ( faceIndex % 2 ? -1 : 1 );
500       break;
501     default:;
502     }
503   }
504   return ind;
505 }
506
507 //=======================================================================
508 //function : IsLinked
509 //purpose  : return true if theNode1 is linked with theNode2
510 //=======================================================================
511
512 bool SMDS_VolumeTool::IsLinked (const SMDS_MeshNode* theNode1,
513                                 const SMDS_MeshNode* theNode2) const
514 {
515   if ( !myVolume )
516     return false;
517
518   // find nodes indices
519   int i1 = -1, i2 = -1;
520   for ( int i = 0; i < myVolumeNbNodes; i++ ) {
521     if ( myVolumeNodes[ i ] == theNode1 )
522       i1 = i;
523     else if ( myVolumeNodes[ i ] == theNode2 )
524       i2 = i;
525   }
526   return IsLinked( i1, i2 );
527 }
528
529 //=======================================================================
530 //function : IsLinked
531 //purpose  : return true if the node with theNode1Index is linked
532 //           with the node with theNode2Index
533 //=======================================================================
534
535 bool SMDS_VolumeTool::IsLinked (const int theNode1Index,
536                                 const int theNode2Index) const
537 {
538   int minInd = theNode1Index < theNode2Index ? theNode1Index : theNode2Index;
539   int maxInd = theNode1Index < theNode2Index ? theNode2Index : theNode1Index;
540
541   if ( minInd < 0 || maxInd > myVolumeNbNodes - 1 || maxInd == minInd )
542     return false;
543
544   switch ( myVolumeNbNodes ) {
545   case 4:
546     return true;
547   case 6:
548     switch ( maxInd - minInd ) {
549     case 1: return minInd != 2;
550     case 2: return minInd == 0 || minInd == 3;
551     case 3: return true;
552     default:;
553     }
554     break;
555   case 8:
556     switch ( maxInd - minInd ) {
557     case 1: return minInd != 3;
558     case 3: return minInd == 0 || minInd == 4;
559     case 4: return true;
560     default:;
561     }
562     break;
563   default:;
564   }
565   return false;
566 }
567
568 //=======================================================================
569 //function : GetNodeIndex
570 //purpose  : Return an index of theNode
571 //=======================================================================
572
573 int SMDS_VolumeTool::GetNodeIndex(const SMDS_MeshNode* theNode) const
574 {
575   if ( myVolume ) {
576     for ( int i = 0; i < myVolumeNbNodes; i++ ) {
577       if ( myVolumeNodes[ i ] == theNode )
578         return i;
579     }
580   }
581   return -1;
582 }
583
584
585 //=======================================================================
586 //function : IsFreeFace
587 //purpose  : check that only one volume is build on the face nodes
588 //=======================================================================
589
590 bool SMDS_VolumeTool::IsFreeFace( int faceIndex )
591 {
592   const int free = true;
593   if ( !setFace( faceIndex ))
594     return !free;
595
596   const SMDS_MeshNode** nodes = GetFaceNodes( faceIndex );
597   int nbFaceNodes = NbFaceNodes( faceIndex );
598
599   // evaluate nb of face nodes shared by other volume
600   int maxNbShared = -1;
601   typedef map< const SMDS_MeshElement*, int > TElemIntMap;
602   TElemIntMap volNbShared;
603   TElemIntMap::iterator vNbIt;
604   for ( int iNode = 0; iNode < nbFaceNodes; iNode++ )
605   {
606     const SMDS_MeshNode* n = nodes[ iNode ];
607     SMDS_ElemIteratorPtr eIt = n->GetInverseElementIterator();
608     while ( eIt->more() ) {
609       const SMDS_MeshElement* elem = eIt->next();
610       if ( elem != myVolume && elem->GetType() == SMDSAbs_Volume ) {
611         int nbShared = 1;
612         vNbIt = volNbShared.find( elem );
613         if ( vNbIt == volNbShared.end() )
614           volNbShared.insert ( TElemIntMap::value_type( elem, nbShared ));
615         else
616           nbShared = ++(*vNbIt).second;
617         if ( nbShared > maxNbShared )
618           maxNbShared = nbShared;
619       }
620     }
621   }
622   if ( maxNbShared < 3 )
623     return free; // is free
624
625   // find volumes laying on the opposite side of the face
626   // and sharing all nodes
627   XYZ intNormal; // internal normal
628   GetFaceNormal( faceIndex, intNormal.x, intNormal.y, intNormal.z );
629   if ( IsFaceExternal( faceIndex ))
630     intNormal = XYZ( -intNormal.x, -intNormal.y, -intNormal.z );
631   XYZ p0 ( nodes[0] ), baryCenter;
632   for ( vNbIt = volNbShared.begin(); vNbIt != volNbShared.end(); vNbIt++ )
633   {
634     int nbShared = (*vNbIt).second;
635     if ( nbShared >= 3 ) {
636       SMDS_VolumeTool volume( (*vNbIt).first );
637       volume.GetBaryCenter( baryCenter.x, baryCenter.y, baryCenter.z );
638       XYZ intNormal2( baryCenter - p0 );
639       if ( intNormal.Dot( intNormal2 ) < 0 )
640         continue; // opposite side
641     }
642     // remove a volume from volNbShared map
643     volNbShared.erase( vNbIt );
644   }
645   // here volNbShared contains only volumes laying on the
646   // opposite side of the face
647   if ( volNbShared.empty() )
648     return free; // is free
649
650   // check if the whole area of a face is shared
651   bool isShared[] = { false, false, false, false }; // 4 triangle parts of a quadrangle
652   for ( vNbIt = volNbShared.begin(); vNbIt != volNbShared.end(); vNbIt++ )
653   {
654     SMDS_VolumeTool volume( (*vNbIt).first );
655     bool prevLinkShared = false;
656     int nbSharedLinks = 0;
657     for ( int iNode = 0; iNode < nbFaceNodes; iNode++ )
658     {
659       bool linkShared = volume.IsLinked( nodes[ iNode ], nodes[ iNode + 1] );
660       if ( linkShared )
661         nbSharedLinks++;
662       if ( linkShared && prevLinkShared &&
663           volume.IsLinked( nodes[ iNode - 1 ], nodes[ iNode + 1] ))
664         isShared[ iNode ] = true;
665       prevLinkShared = linkShared;
666     }
667     if ( nbSharedLinks == nbFaceNodes )
668       return !free; // is not free
669     if ( nbFaceNodes == 4 ) {
670       // check traingle parts 1 & 3
671       if ( isShared[1] && isShared[3] )
672         return !free; // is not free
673       // check traingle parts 0 & 2;
674       // 0 part could not be checked in the loop; check it here
675       if ( isShared[2] && prevLinkShared &&
676           volume.IsLinked( nodes[ 0 ], nodes[ 1 ] ) &&
677           volume.IsLinked( nodes[ 1 ], nodes[ 3 ] ) )
678         return !free; // is not free
679     }
680   }
681   return free;
682 }
683
684 //=======================================================================
685 //function : GetFaceIndex
686 //purpose  : Return index of a face formed by theFaceNodes
687 //=======================================================================
688
689 int SMDS_VolumeTool::GetFaceIndex( const set<const SMDS_MeshNode*>& theFaceNodes )
690 {
691   for ( int iFace = 0; iFace < myNbFaces; iFace++ ) {
692     const SMDS_MeshNode** nodes = GetFaceNodes( iFace );
693     int nbFaceNodes = NbFaceNodes( iFace );
694     set<const SMDS_MeshNode*> nodeSet;
695     for ( int iNode = 0; iNode < nbFaceNodes; iNode++ )
696       nodeSet.insert( nodes[ iNode ] );
697     if ( theFaceNodes == nodeSet )
698       return iFace;
699   }
700   return -1;
701 }
702
703 //=======================================================================
704 //function : GetFaceIndex
705 //purpose  : Return index of a face formed by theFaceNodes
706 //=======================================================================
707
708 int SMDS_VolumeTool::GetFaceIndex( const set<int>& theFaceNodesIndices )
709 {
710   for ( int iFace = 0; iFace < myNbFaces; iFace++ ) {
711     const int* nodes = GetFaceNodesIndices( iFace );
712     int nbFaceNodes = NbFaceNodes( iFace );
713     set<int> nodeSet;
714     for ( int iNode = 0; iNode < nbFaceNodes; iNode++ )
715       nodeSet.insert( nodes[ iNode ] );
716     if ( theFaceNodesIndices == nodeSet )
717       return iFace;
718   }
719   return -1;
720 }
721
722 //=======================================================================
723 //function : setFace
724 //purpose  : 
725 //=======================================================================
726
727 bool SMDS_VolumeTool::setFace( int faceIndex )
728 {
729   if ( !myVolume )
730     return false;
731
732   if ( myCurFace == faceIndex )
733     return true;
734
735   if ( faceIndex < 0 || faceIndex >= NbFaces() )
736     return false;
737
738   // choose face node indices
739   switch ( myVolumeNbNodes ) {
740   case 4:
741     if ( myExternalFaces )
742       myFaceNodeIndices = myVolForward ? Tetra_R[ faceIndex ] : Tetra_F[ faceIndex ];
743     else if ( myForwardFaces )
744       myFaceNodeIndices = myVolForward ? Tetra_F[ faceIndex ] : Tetra_R[ faceIndex ];
745     else
746       myFaceNodeIndices = Tetra_F[ faceIndex ];
747     break;
748   case 6:
749     if ( myExternalFaces )
750       myFaceNodeIndices = myVolForward ? Penta_FE[ faceIndex ] : Penta_RE[ faceIndex ];
751     else if ( myForwardFaces )
752       myFaceNodeIndices = myVolForward ? Penta_F[ faceIndex ] : Penta_R[ faceIndex ];
753     else
754       myFaceNodeIndices = Penta_F[ faceIndex ];
755     break;
756   case 8:
757     if ( myExternalFaces )
758       myFaceNodeIndices = myVolForward ? Hexa_FE[ faceIndex ] : Hexa_RE[ faceIndex ];
759     else if ( myForwardFaces )
760       myFaceNodeIndices = myVolForward ? Hexa_F[ faceIndex ] : Hexa_R[ faceIndex ];
761     else
762       myFaceNodeIndices = Hexa_F[ faceIndex ];
763     break;
764   default: return false;
765   }
766
767   // set face nodes
768   int iNode, nbNode = myFaceNbNodes[ faceIndex ];
769   for ( iNode = 0; iNode <= nbNode; iNode++ )
770     myFaceNodes[ iNode ] = myVolumeNodes[ myFaceNodeIndices[ iNode ]];
771
772   myCurFace = faceIndex;
773
774   return true;
775 }