Salome HOME
0fa7d2f0ffbd33e241b8d6d17e328147af7b2108
[modules/smesh.git] / src / SMDS / SMDS_VolumeTool.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      : SMDS_VolumeTool.cxx
21 // Created   : Tue Jul 13 12:22:13 2004
22 // Author    : Edward AGAPOV (eap)
23 // Copyright : Open CASCADE
24
25 #ifdef _MSC_VER
26 #pragma warning(disable:4786)
27 #endif
28
29 #include "SMDS_VolumeTool.hxx"
30
31 #include "SMDS_MeshElement.hxx"
32 #include "SMDS_MeshNode.hxx"
33 #include "SMDS_PolyhedralVolumeOfNodes.hxx"
34
35 #include "utilities.h"
36
37 #include <map>
38 #include <float.h>
39 #include <math.h>
40
41 using namespace std;
42
43 // ======================================================
44 // Node indices in faces depending on volume orientation
45 // making most faces normals external
46 // ======================================================
47
48 /*
49 //           N3
50 //           +
51 //          /|\
52 //         / | \
53 //        /  |  \
54 //    N0 +---|---+ N1                TETRAHEDRON
55 //       \   |   /
56 //        \  |  /
57 //         \ | /
58 //          \|/
59 //           +
60 //           N2
61 */
62 static int Tetra_F [4][4] = { // FORWARD == EXTERNAL
63   { 0, 1, 2, 0 },              // All faces have external normals
64   { 0, 3, 1, 0 },
65   { 1, 3, 2, 1 },
66   { 0, 2, 3, 0 }}; 
67 static int Tetra_R [4][4] = { // REVERSED
68   { 0, 1, 2, 0 },             // All faces but a bottom have external normals
69   { 0, 1, 3, 0 },
70   { 1, 2, 3, 1 },
71   { 0, 3, 2, 0 }};
72 static int Tetra_RE [4][4] = { // REVERSED -> FORWARD (EXTERNAL)
73   { 0, 2, 1, 0 },              // All faces have external normals
74   { 0, 1, 3, 0 },
75   { 1, 2, 3, 1 },
76   { 0, 3, 2, 0 }};
77 static int Tetra_nbN [] = { 3, 3, 3, 3 };
78
79 //
80 //     PYRAMID
81 //
82 static int Pyramid_F [5][5] = { // FORWARD == EXTERNAL
83   { 0, 1, 2, 3, 0 },            // All faces have external normals
84   { 0, 4, 1, 0, 4 },
85   { 1, 4, 2, 1, 4 },
86   { 2, 4, 3, 2, 4 },
87   { 3, 4, 0, 3, 4 }}; 
88 static int Pyramid_R [5][5] = { // REVERSED
89   { 0, 1, 2, 3, 0 },            // All faces but a bottom have external normals
90   { 0, 1, 4, 0, 4 },
91   { 1, 2, 4, 1, 4 },
92   { 2, 3, 4, 2, 4 },
93   { 3, 0, 4, 3, 4 }}; 
94 static int Pyramid_RE [5][5] = { // REVERSED -> FORWARD (EXTERNAL)
95   { 0, 3, 2, 1, 0 },             // All faces but a bottom have external normals
96   { 0, 1, 4, 0, 4 },
97   { 1, 2, 4, 1, 4 },
98   { 2, 3, 4, 2, 4 },
99   { 3, 0, 4, 3, 4 }}; 
100 static int Pyramid_nbN [] = { 4, 3, 3, 3, 3 };
101
102 /*   
103 //            + N4
104 //           /|\
105 //          / | \
106 //         /  |  \
107 //        /   |   \
108 //    N3 +---------+ N5
109 //       |    |    |
110 //       |    + N1 |
111 //       |   / \   |                PENTAHEDRON
112 //       |  /   \  |
113 //       | /     \ |
114 //       |/       \|
115 //    N0 +---------+ N2
116 */
117 static int Penta_F [5][5] = { // FORWARD
118   { 0, 1, 2, 0, 0 },          // Top face has an internal normal, other - external
119   { 3, 4, 5, 3, 3 },          // 0 is bottom, 1 is top face
120   { 0, 2, 5, 3, 0 },
121   { 1, 4, 5, 2, 1 },
122   { 0, 3, 4, 1, 0 }}; 
123 static int Penta_R [5][5] = { // REVERSED
124   { 0, 1, 2, 0, 0 },          // Bottom face has an internal normal, other - external
125   { 3, 4, 5, 3, 3 },          // 0 is bottom, 1 is top face
126   { 0, 3, 5, 2, 0 },
127   { 1, 2, 5, 4, 1 },
128   { 0, 1, 4, 3, 0 }}; 
129 static int Penta_FE [5][5] = { // FORWARD -> EXTERNAL
130   { 0, 1, 2, 0, 0 },
131   { 3, 5, 4, 3, 3 },
132   { 0, 2, 5, 3, 0 },
133   { 1, 4, 5, 2, 1 },
134   { 0, 3, 4, 1, 0 }}; 
135 static int Penta_RE [5][5] = { // REVERSED -> EXTERNAL
136   { 0, 2, 1, 0, 0 },
137   { 3, 4, 5, 3, 3 },
138   { 0, 3, 5, 2, 0 },
139   { 1, 2, 5, 4, 1 },
140   { 0, 1, 4, 3, 0 }}; 
141 static int Penta_nbN [] = { 3, 3, 4, 4, 4 };
142
143 /*
144 //         N5+----------+N6
145 //          /|         /|
146 //         / |        / |
147 //        /  |       /  |
148 //     N4+----------+N7 |
149 //       |   |      |   |           HEXAHEDRON
150 //       |   |      |   |
151 //       |   |      |   |
152 //       | N1+------|---+N2
153 //       |  /       |  /
154 //       | /        | /
155 //       |/         |/
156 //     N0+----------+N3
157 */
158 static int Hexa_F [6][5] = { // FORWARD
159   { 0, 1, 2, 3, 0 },         // opposite faces are neighbouring,
160   { 4, 5, 6, 7, 4 },         // odd face(1,3,5) normal is internal, even(0,2,4) - external
161   { 1, 0, 4, 5, 1 },         // same index nodes of opposite faces are linked
162   { 2, 3, 7, 6, 2 }, 
163   { 0, 3, 7, 4, 0 }, 
164   { 1, 2, 6, 5, 1 }};
165 // static int Hexa_R [6][5] = { // REVERSED
166 //   { 0, 3, 2, 1, 0 },         // opposite faces are neighbouring,
167 //   { 4, 7, 6, 5, 4 },         // odd face(1,3,5) normal is external, even(0,2,4) - internal
168 //   { 1, 5, 4, 0, 1 },         // same index nodes of opposite faces are linked
169 //   { 2, 6, 7, 3, 2 }, 
170 //   { 0, 4, 7, 3, 0 }, 
171 //   { 1, 5, 6, 2, 1 }};
172 static int Hexa_FE [6][5] = { // FORWARD -> EXTERNAL
173   { 0, 1, 2, 3, 0 } ,         // opposite faces are neighbouring,
174   { 4, 7, 6, 5, 4 },          // all face normals are external,
175   { 0, 4, 5, 1, 0 },          // links in opposite faces: 0-0, 1-3, 2-2, 3-1
176   { 3, 2, 6, 7, 3 }, 
177   { 0, 3, 7, 4, 0 },
178   { 1, 5, 6, 2, 1 }};
179 static int Hexa_RE [6][5] = { // REVERSED -> EXTERNAL
180   { 0, 3, 2, 1, 0 },          // opposite faces are neighbouring,
181   { 4, 5, 6, 7, 4 },          // all face normals are external,
182   { 0, 1, 5, 4, 0 },          // links in opposite faces: 0-0, 1-3, 2-2, 3-1
183   { 3, 7, 6, 2, 3 }, 
184   { 0, 4, 7, 3, 0 },
185   { 1, 2, 6, 5, 1 }};
186 static int Hexa_nbN [] = { 4, 4, 4, 4, 4, 4 };
187
188
189 /*
190 //           N3
191 //           +
192 //          /|\
193 //        7/ | \8
194 //        /  |4 \                    QUADRATIC
195 //    N0 +---|---+ N1                TETRAHEDRON
196 //       \   +9  /
197 //        \  |  /
198 //        6\ | /5
199 //          \|/
200 //           +
201 //           N2
202 */
203 static int QuadTetra_F [4][7] = { // FORWARD == EXTERNAL
204   { 0, 4, 1, 5, 2, 6, 0 },        // All faces have external normals
205   { 0, 7, 3, 8, 1, 4, 0 },
206   { 1, 8, 3, 9, 2, 5, 1 },
207   { 0, 6, 2, 9, 3, 7, 0 }}; 
208 static int QuadTetra_R [4][7] = { // REVERSED
209   { 0, 4, 1, 5, 2, 6, 0 },        // All faces but a bottom have external normals
210   { 0, 4, 1, 8, 3, 7, 0 },
211   { 1, 5, 2, 9, 3, 8, 1 },
212   { 0, 7, 3, 9, 2, 6, 0 }};
213 static int QuadTetra_RE [4][7] = { // REVERSED -> FORWARD (EXTERNAL)
214   { 0, 6, 2, 5, 1, 4, 0 },              // All faces have external normals
215   { 0, 4, 1, 8, 3, 7, 0 },
216   { 1, 5, 2, 9, 3, 8, 1 },
217   { 0, 7, 3, 9, 2, 6, 0 }};
218 static int QuadTetra_nbN [] = { 6, 6, 6, 6 };
219
220 //
221 //     QUADRATIC
222 //     PYRAMID
223 //
224 //            +4
225 //
226 //            
227 //       10+-----+11
228 //         |     |        9 - middle point for (0,4) etc.
229 //         |     |
230 //        9+-----+12
231 //
232 //            6
233 //      1+----+----+2
234 //       |         |
235 //       |         |
236 //      5+         +7
237 //       |         |
238 //       |         |
239 //      0+----+----+3
240 //            8
241 static int QuadPyram_F [5][9] = {  // FORWARD == EXTERNAL
242   { 0, 5, 1, 6, 2, 7, 3, 8, 0 },   // All faces have external normals
243   { 0, 9, 4, 10,1, 5, 0, 4, 4 },
244   { 1, 10,4, 11,2, 6, 1, 4, 4 },
245   { 2, 11,4, 12,3, 7, 2, 4, 4 },
246   { 3, 12,4, 9, 0, 8, 3, 4, 4 }}; 
247 static int QuadPyram_R [5][9] = {  // REVERSED
248   { 0, 5, 1, 6, 2, 7, 3, 8, 0 },   // All faces but a bottom have external normals
249   { 0, 5, 1, 10,4, 9, 0, 4, 4 },
250   { 1, 6, 2, 11,4, 10,1, 4, 4 },
251   { 2, 7, 3, 12,4, 11,2, 4, 4 },
252   { 3, 8, 0, 9, 4, 12,3, 4, 4 }}; 
253 static int QuadPyram_RE [5][9] = { // REVERSED -> FORWARD (EXTERNAL)
254   { 0, 8, 3, 7, 2, 6, 1, 5, 0 },   // All faces but a bottom have external normals
255   { 0, 5, 1, 10,4, 9, 0, 4, 4 },
256   { 1, 6, 2, 11,4, 10,1, 4, 4 },
257   { 2, 7, 3, 12,4, 11,2, 4, 4 },
258   { 3, 8, 0, 9, 4, 12,3, 4, 4 }}; 
259 static int QuadPyram_nbN [] = { 8, 6, 6, 6, 6 };
260
261 /*   
262 //            + N4
263 //           /|\
264 //         9/ | \10
265 //         /  |  \
266 //        /   |   \
267 //    N3 +----+----+ N5
268 //       |    |11  |
269 //       |    |    |
270 //       |    +13  |                QUADRATIC
271 //       |    |    |                PENTAHEDRON
272 //       |    |    |
273 //       |    |    |
274 //       |    |    |
275 //     12+    |    +14
276 //       |    |    |
277 //       |    |    |
278 //       |    + N1 |
279 //       |   / \   |               
280 //       | 6/   \7 |
281 //       | /     \ |
282 //       |/       \|
283 //    N0 +---------+ N2
284 //            8
285 */
286 static int QuadPenta_F [5][9] = {  // FORWARD
287   { 0, 6, 1, 7, 2, 8, 0, 0, 0 },   // Top face has an internal normal, other - external
288   { 3, 9, 4, 10,5, 11,3, 3, 3 },   // 0 is bottom, 1 is top face
289   { 0, 8, 2, 14,5, 11,3, 12,0 },
290   { 1, 13,4, 10,5, 14,2, 7, 1 },
291   { 0, 12,3, 9, 4, 13,1, 6, 0 }}; 
292 static int QuadPenta_R [5][9] = { // REVERSED
293   { 0, 6, 1, 7, 2, 8, 0, 0, 0 },  // Bottom face has an internal normal, other - external
294   { 3, 9, 4, 10,5, 11,3, 3, 3 },  // 0 is bottom, 1 is top face
295   { 0, 12,3, 11,5, 14,2, 8, 0 },
296   { 1, 7, 2, 14,5, 10,4, 13,1 },
297   { 0, 6, 1, 13,4, 9, 3, 12,0 }}; 
298 static int QuadPenta_FE [5][9] = { // FORWARD -> EXTERNAL
299   { 0, 6, 1, 7, 2, 8, 0, 0, 0 },
300   { 3,11, 5, 10,4, 9, 3, 3, 3 },
301   { 0, 8, 2, 14,5, 11,3, 12,0 },
302   { 1, 13,4, 10,5, 14,2, 7, 1 },
303   { 0, 12,3, 9, 4, 13,1, 6, 0 }}; 
304 static int QuadPenta_RE [5][9] = { // REVERSED -> EXTERNAL
305   { 0, 8, 2, 7, 1, 6, 0, 0, 0 },
306   { 3, 9, 4, 10,5, 11,3, 3, 3 },
307   { 0, 12,3, 11,5, 14,2, 8, 0 },
308   { 1, 7, 2, 14,5, 10,4, 13,1 },
309   { 0, 6, 1, 13,4, 9, 3, 12,0 }}; 
310 static int QuadPenta_nbN [] = { 6, 6, 8, 8, 8 };
311
312 /*
313 //                 13
314 //         N5+-----+-----+N6
315 //          /|          /|
316 //       12+ |       14+ |
317 //        /  |        /  |
318 //     N4+-----+-----+N7 |           QUADRATIC
319 //       |   | 15    |   |           HEXAHEDRON
320 //       |   |       |   |
321 //       | 17+       |   +18
322 //       |   |       |   |
323 //       |   |       |   |
324 //       |   |       |   |
325 //     16+   |       +19 |
326 //       |   |       |   |
327 //       |   |     9 |   |
328 //       | N1+-----+-|---+N2
329 //       |  /        |  /
330 //       | +8        | +10
331 //       |/          |/
332 //     N0+-----+-----+N3
333 //             11
334 */
335 static int QuadHexa_F [6][9] = {  // FORWARD
336   { 0, 8, 1, 9, 2, 10,3, 11,0 },  // opposite faces are neighbouring,
337   { 4, 12,5, 13,6, 14,7, 15,4 },  // odd face(1,3,5) normal is internal, even(0,2,4) - external
338   { 1, 8, 0, 16,4, 12,5, 17,1 },  // same index nodes of opposite faces are linked
339   { 2, 10,3, 19,7, 14,6, 18,2 }, 
340   { 0, 11,3, 19,7, 15,4, 16,0 }, 
341   { 1, 9, 2, 18,6, 13,5, 17,1 }};
342 // static int Hexa_R [6][5] = { // REVERSED
343 //   { 0, 3, 2, 1, 0 },         // opposite faces are neighbouring,
344 //   { 4, 7, 6, 5, 4 },         // odd face(1,3,5) normal is external, even(0,2,4) - internal
345 //   { 1, 5, 4, 0, 1 },         // same index nodes of opposite faces are linked
346 //   { 2, 6, 7, 3, 2 }, 
347 //   { 0, 4, 7, 3, 0 }, 
348 //   { 1, 5, 6, 2, 1 }};
349 static int QuadHexa_FE [6][9] = {  // FORWARD -> EXTERNAL
350   { 0, 8, 1, 9, 2, 10,3, 11,0 },   // opposite faces are neighbouring,
351   { 4, 15,7, 14,6, 13,5, 12,4 },   // all face normals are external,
352   { 0, 16,4, 12,5, 17,1, 8, 0 },   // links in opposite faces: 0-0, 1-3, 2-2, 3-1
353   { 3, 10,2, 18,6, 14,7, 19,3 }, 
354   { 0, 11,3, 19,7, 15,4, 16,0 },
355   { 1, 17,5, 13,6, 18,2, 9, 1 }};
356 static int QuadHexa_RE [6][9] = {  // REVERSED -> EXTERNAL
357   { 0, 11,3, 10,2, 9, 1, 8, 0 },   // opposite faces are neighbouring,
358   { 4, 12,5, 13,6, 14,7, 15,4 },   // all face normals are external,
359   { 0, 8, 1, 17,5, 12,4, 16,0 },   // links in opposite faces: 0-0, 1-3, 2-2, 3-1
360   { 3, 19,7, 14,6, 18,2, 10,3 }, 
361   { 0, 16,4, 15,7, 19,3, 11,0 },
362   { 1, 9, 2, 18,6, 13,5, 17,1 }};
363 static int QuadHexa_nbN [] = { 8, 8, 8, 8, 8, 8 };
364
365
366 // ========================================================
367 // to perform some calculations without linkage to CASCADE
368 // ========================================================
369 struct XYZ {
370   double x;
371   double y;
372   double z;
373   XYZ()                               { x = 0; y = 0; z = 0; }
374   XYZ( double X, double Y, double Z ) { x = X; y = Y; z = Z; }
375   XYZ( const XYZ& other )             { x = other.x; y = other.y; z = other.z; }
376   XYZ( const SMDS_MeshNode* n )       { x = n->X(); y = n->Y(); z = n->Z(); }
377   XYZ operator-( const XYZ& other );
378   XYZ Crossed( const XYZ& other );
379   double Dot( const XYZ& other );
380   double Magnitude();
381 };
382 XYZ XYZ::operator-( const XYZ& Right ) {
383   return XYZ(x - Right.x, y - Right.y, z - Right.z);
384 }
385 XYZ XYZ::Crossed( const XYZ& Right ) {
386   return XYZ (y * Right.z - z * Right.y,
387               z * Right.x - x * Right.z,
388               x * Right.y - y * Right.x);
389 }
390 double XYZ::Dot( const XYZ& Other ) {
391   return(x * Other.x + y * Other.y + z * Other.z);
392 }
393 double XYZ::Magnitude() {
394   return sqrt (x * x + y * y + z * z);
395 }
396
397 //=======================================================================
398 //function : SMDS_VolumeTool
399 //purpose  : 
400 //=======================================================================
401
402 SMDS_VolumeTool::SMDS_VolumeTool ()
403      : myVolume( 0 ),
404        myPolyedre( 0 ),
405        myVolForward( true ),
406        myNbFaces( 0 ),
407        myVolumeNbNodes( 0 ),
408        myVolumeNodes( NULL ),
409        myExternalFaces( false ),
410        myFaceNbNodes( 0 ),
411        myCurFace( -1 ),
412        myFaceNodeIndices( NULL ),
413        myFaceNodes( NULL )
414 {
415 }
416
417 //=======================================================================
418 //function : SMDS_VolumeTool
419 //purpose  : 
420 //=======================================================================
421
422 SMDS_VolumeTool::SMDS_VolumeTool (const SMDS_MeshElement* theVolume)
423      : myVolume( 0 ),
424        myPolyedre( 0 ),
425        myVolForward( true ),
426        myNbFaces( 0 ),
427        myVolumeNbNodes( 0 ),
428        myVolumeNodes( NULL ),
429        myExternalFaces( false ),
430        myFaceNbNodes( 0 ),
431        myCurFace( -1 ),
432        myFaceNodeIndices( NULL ),
433        myFaceNodes( NULL )
434 {
435   Set( theVolume );
436 }
437
438 //=======================================================================
439 //function : SMDS_VolumeTool
440 //purpose  : 
441 //=======================================================================
442
443 SMDS_VolumeTool::~SMDS_VolumeTool()
444 {
445   if (myVolumeNodes != NULL) {
446     delete [] myVolumeNodes;
447     myVolumeNodes = NULL;
448   }
449   if (myFaceNodes != NULL) {
450     delete [] myFaceNodes;
451     myFaceNodes = NULL;
452   }
453 }
454
455 //=======================================================================
456 //function : SetVolume
457 //purpose  : Set volume to iterate on
458 //=======================================================================
459
460 bool SMDS_VolumeTool::Set (const SMDS_MeshElement* theVolume)
461 {
462   myVolume = 0;
463   myPolyedre = 0;
464
465   myVolForward = true;
466   myNbFaces = 0;
467   myVolumeNbNodes = 0;
468   if (myVolumeNodes != NULL) {
469     delete [] myVolumeNodes;
470     myVolumeNodes = NULL;
471   }
472
473   myExternalFaces = false;
474   myFaceNbNodes = 0;
475
476   myCurFace = -1;
477   myFaceNodeIndices = NULL;
478   if (myFaceNodes != NULL) {
479     delete [] myFaceNodes;
480     myFaceNodes = NULL;
481   }
482
483   if ( theVolume && theVolume->GetType() == SMDSAbs_Volume )
484   {
485     myVolume = theVolume;
486
487     myNbFaces = theVolume->NbFaces();
488     myVolumeNbNodes = theVolume->NbNodes();
489
490     // set volume nodes
491     int iNode = 0;
492     myVolumeNodes = new const SMDS_MeshNode* [myVolumeNbNodes];
493     SMDS_ElemIteratorPtr nodeIt = myVolume->nodesIterator();
494     while ( nodeIt->more() ) {
495       myVolumeNodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
496     }
497
498     if (myVolume->IsPoly()) {
499       myPolyedre = static_cast<const SMDS_PolyhedralVolumeOfNodes*>( myVolume );
500       if (!myPolyedre) {
501         MESSAGE("Warning: bad volumic element");
502         return false;
503       }
504     }
505     else {
506       switch ( myVolumeNbNodes ) {
507       case 4:
508       case 5:
509       case 6:
510       case 8:
511       case 10:
512       case 13:
513       case 15:
514       case 20: {
515         // define volume orientation
516         XYZ botNormal;
517         GetFaceNormal( 0, botNormal.x, botNormal.y, botNormal.z );
518         const SMDS_MeshNode* topNode = myVolumeNodes[ myVolumeNbNodes - 1 ];
519         const SMDS_MeshNode* botNode = myVolumeNodes[ 0 ];
520         XYZ upDir (topNode->X() - botNode->X(),
521                    topNode->Y() - botNode->Y(),
522                    topNode->Z() - botNode->Z() );
523         myVolForward = ( botNormal.Dot( upDir ) < 0 );
524         break;
525       }
526       default:
527         break;
528       }
529     }
530   }
531   return ( myVolume != 0 );
532 }
533
534 //=======================================================================
535 //function : Inverse
536 //purpose  : Inverse volume
537 //=======================================================================
538
539 #define SWAP_NODES(nodes,i1,i2)           \
540 {                                         \
541   const SMDS_MeshNode* tmp = nodes[ i1 ]; \
542   nodes[ i1 ] = nodes[ i2 ];              \
543   nodes[ i2 ] = tmp;                      \
544 }
545 void SMDS_VolumeTool::Inverse ()
546 {
547   if ( !myVolume ) return;
548
549   if (myVolume->IsPoly()) {
550     MESSAGE("Warning: attempt to inverse polyhedral volume");
551     return;
552   }
553
554   myVolForward = !myVolForward;
555   myCurFace = -1;
556
557   // inverse top and bottom faces
558   switch ( myVolumeNbNodes ) {
559   case 4:
560     SWAP_NODES( myVolumeNodes, 1, 2 );
561     break;
562   case 5:
563     SWAP_NODES( myVolumeNodes, 1, 3 );
564     break;
565   case 6:
566     SWAP_NODES( myVolumeNodes, 1, 2 );
567     SWAP_NODES( myVolumeNodes, 4, 5 );
568     break;
569   case 8:
570     SWAP_NODES( myVolumeNodes, 1, 3 );
571     SWAP_NODES( myVolumeNodes, 5, 7 );
572     break;
573
574   case 10:
575     SWAP_NODES( myVolumeNodes, 1, 2 );
576     SWAP_NODES( myVolumeNodes, 4, 6 );
577     SWAP_NODES( myVolumeNodes, 8, 9 );
578     break;
579   case 13:
580     SWAP_NODES( myVolumeNodes, 1, 3 );
581     SWAP_NODES( myVolumeNodes, 5, 8 );
582     SWAP_NODES( myVolumeNodes, 6, 7 );
583     SWAP_NODES( myVolumeNodes, 10, 12 );
584     break;
585   case 15:
586     SWAP_NODES( myVolumeNodes, 1, 2 );
587     SWAP_NODES( myVolumeNodes, 4, 5 );
588     SWAP_NODES( myVolumeNodes, 6, 8 );
589     SWAP_NODES( myVolumeNodes, 9, 11 );
590     SWAP_NODES( myVolumeNodes, 13, 14 );
591     break;
592   case 20:
593     SWAP_NODES( myVolumeNodes, 1, 3 );
594     SWAP_NODES( myVolumeNodes, 5, 7 );
595     SWAP_NODES( myVolumeNodes, 8, 11 );
596     SWAP_NODES( myVolumeNodes, 9, 10 );
597     SWAP_NODES( myVolumeNodes, 12, 15 );
598     SWAP_NODES( myVolumeNodes, 13, 14 );
599     SWAP_NODES( myVolumeNodes, 17, 19 );
600     break;
601   default:;
602   }
603 }
604
605 //=======================================================================
606 //function : GetVolumeType
607 //purpose  : 
608 //=======================================================================
609
610 SMDS_VolumeTool::VolumeType SMDS_VolumeTool::GetVolumeType() const
611 {
612   if ( myPolyedre )
613     return POLYHEDA;
614
615   if ( myVolume ) {
616 //    static const VolumeType types[] = {
617 //      TETRA,     // myVolumeNbNodes = 4
618 //      PYRAM,     // myVolumeNbNodes = 5
619 //      PENTA,     // myVolumeNbNodes = 6
620 //      UNKNOWN,   // myVolumeNbNodes = 7
621 //      HEXA       // myVolumeNbNodes = 8
622 //    };
623 //    return types[ myVolumeNbNodes - 4 ];
624     switch(myVolumeNbNodes) {
625     case 4: return TETRA; break;
626     case 5: return PYRAM; break;
627     case 6: return PENTA; break;
628     case 8: return HEXA; break;
629     case 10: return QUAD_TETRA; break;
630     case 13: return QUAD_PYRAM; break;
631     case 15: return QUAD_PENTA; break;
632     case 20: return QUAD_HEXA; break;
633     default: break;
634     }
635   }
636
637   return UNKNOWN;
638 }
639
640 //=======================================================================
641 //function : getTetraVolume
642 //purpose  : 
643 //=======================================================================
644
645 static double getTetraVolume(const SMDS_MeshNode* n1,
646                              const SMDS_MeshNode* n2,
647                              const SMDS_MeshNode* n3,
648                              const SMDS_MeshNode* n4)
649 {
650   double X1 = n1->X();
651   double Y1 = n1->Y();
652   double Z1 = n1->Z();
653
654   double X2 = n2->X();
655   double Y2 = n2->Y();
656   double Z2 = n2->Z();
657
658   double X3 = n3->X();
659   double Y3 = n3->Y();
660   double Z3 = n3->Z();
661
662   double X4 = n4->X();
663   double Y4 = n4->Y();
664   double Z4 = n4->Z();
665
666   double Q1 = -(X1-X2)*(Y3*Z4-Y4*Z3);
667   double Q2 =  (X1-X3)*(Y2*Z4-Y4*Z2);
668   double R1 = -(X1-X4)*(Y2*Z3-Y3*Z2);
669   double R2 = -(X2-X3)*(Y1*Z4-Y4*Z1);
670   double S1 =  (X2-X4)*(Y1*Z3-Y3*Z1);
671   double S2 = -(X3-X4)*(Y1*Z2-Y2*Z1);
672
673   return (Q1+Q2+R1+R2+S1+S2)/6.0;
674 }
675
676 //=======================================================================
677 //function : GetSize
678 //purpose  : Return element volume
679 //=======================================================================
680
681 double SMDS_VolumeTool::GetSize() const
682 {
683   double V = 0.;
684   if ( !myVolume )
685     return 0.;
686
687   if ( myVolume->IsPoly() )
688   {
689     if ( !myPolyedre )
690       return 0.;
691
692     // split a polyhedron into tetrahedrons
693
694     SMDS_VolumeTool* me = const_cast< SMDS_VolumeTool* > ( this );
695     XYZ baryCenter;
696     me->GetBaryCenter(baryCenter.x, baryCenter.y, baryCenter.z);
697     SMDS_MeshNode bcNode ( baryCenter.x, baryCenter.y, baryCenter.z );
698
699     for ( int f = 0; f < NbFaces(); ++f )
700     {
701       bool externalFace = me->IsFaceExternal( f ); // it calls setFace()
702       for ( int n = 2; n < myFaceNbNodes; ++n )
703       {
704         double Vn = getTetraVolume( myFaceNodes[ 0 ],
705                                     myFaceNodes[ n-1 ],
706                                     myFaceNodes[ n ],
707                                     & bcNode );
708 ///         cout <<"++++   " << Vn << "   nodes " <<myFaceNodes[ 0 ]->GetID() << " " <<myFaceNodes[ n-1 ]->GetID() << " " <<myFaceNodes[ n ]->GetID() << "        < " << V << endl;
709         V += externalFace ? -Vn : Vn;
710       }
711     }
712   }
713   else 
714   {
715     const static int ind[] = {
716       0, 1, 3, 6, 11, 19, 32, 35, 40};
717     const static int vtab[][4] = {
718       // tetrahedron
719       { 0, 1, 2, 3 },
720       // pyramid
721       { 0, 1, 3, 4 },
722       { 1, 2, 3, 4 },
723       // pentahedron
724       { 0, 1, 2, 3 },
725       { 1, 5, 3, 4 },
726       { 1, 5, 2, 3 },
727       // hexahedron
728       { 1, 4, 3, 0 },
729       { 4, 1, 6, 5 },
730       { 1, 3, 6, 2 },
731       { 4, 6, 3, 7 },
732       { 1, 4, 6, 3 },
733
734       // quadratic tetrahedron
735       { 0, 4, 6, 7 },
736       { 1, 5, 4, 8 },
737       { 2, 6, 5, 9 },
738       { 7, 8, 9, 3 },
739       { 4, 6, 7, 9 },
740       { 4, 5, 6, 9 },
741       { 4, 7, 8, 9 },
742       { 4, 5, 9, 8 },
743       //{ 6, 7, 9, 4 },
744       //{ 5, 6, 9, 4 },
745       //{ 7, 8, 9, 4 },
746       //{ 5, 9, 8, 4 },
747
748       // quadratic pyramid
749       { 0, 5, 8, 9 },
750       { 1, 5,10, 6 },
751       { 2, 6,11, 7 },
752       { 3, 7,12, 8 },
753       { 4, 9,11,10 },
754       { 4, 9,12,11 },
755       { 10, 5, 9, 8 },
756       { 10, 8, 9,12 },
757       { 10, 8,12, 7 },
758       { 10, 7,12,11 },
759       { 10, 7,11, 6 },
760       { 10, 5, 8, 6 },
761       { 10, 6, 8, 7 },
762
763       // quadratic pentahedron
764       { 0, 1, 2, 3 },
765       { 1, 5, 3, 4 },
766       { 1, 5, 2, 3 },
767
768       // quadratic hexahedron
769       { 1, 4, 3, 0 },
770       { 4, 1, 6, 5 },
771       { 1, 3, 6, 2 },
772       { 4, 6, 3, 7 },
773       { 1, 4, 6, 3 }
774     };
775
776     int type = GetVolumeType();
777     int n1 = ind[type];
778     int n2 = ind[type+1];
779
780 //cout<<"n1="<<n1<<" n2="<<n2<<endl;
781     for (int i = n1; i <  n2; i++) {
782 //cout<<"V="<<V<<endl;
783       V -= getTetraVolume( myVolumeNodes[ vtab[i][0] ],
784                            myVolumeNodes[ vtab[i][1] ],
785                            myVolumeNodes[ vtab[i][2] ],
786                            myVolumeNodes[ vtab[i][3] ]);
787     }
788 //cout<<"V="<<V<<endl;
789   }
790   return V;
791 }
792
793 //=======================================================================
794 //function : GetBaryCenter
795 //purpose  : 
796 //=======================================================================
797
798 bool SMDS_VolumeTool::GetBaryCenter(double & X, double & Y, double & Z) const
799 {
800   X = Y = Z = 0.;
801   if ( !myVolume )
802     return false;
803
804   for ( int i = 0; i < myVolumeNbNodes; i++ ) {
805     X += myVolumeNodes[ i ]->X();
806     Y += myVolumeNodes[ i ]->Y();
807     Z += myVolumeNodes[ i ]->Z();
808   }
809   X /= myVolumeNbNodes;
810   Y /= myVolumeNbNodes;
811   Z /= myVolumeNbNodes;
812
813   return true;
814 }
815
816 //=======================================================================
817 //function : SetExternalNormal
818 //purpose  : Node order will be so that faces normals are external
819 //=======================================================================
820
821 void SMDS_VolumeTool::SetExternalNormal ()
822 {
823   myExternalFaces = true;
824   myCurFace = -1;
825 }
826
827 //=======================================================================
828 //function : NbFaceNodes
829 //purpose  : Return number of nodes in the array of face nodes
830 //=======================================================================
831
832 int SMDS_VolumeTool::NbFaceNodes( int faceIndex )
833 {
834     if ( !setFace( faceIndex ))
835       return 0;
836     return myFaceNbNodes;
837 }
838
839 //=======================================================================
840 //function : GetFaceNodes
841 //purpose  : Return pointer to the array of face nodes.
842 //           To comfort link iteration, the array
843 //           length == NbFaceNodes( faceIndex ) + 1 and
844 //           the last node == the first one.
845 //=======================================================================
846
847 const SMDS_MeshNode** SMDS_VolumeTool::GetFaceNodes( int faceIndex )
848 {
849   if ( !setFace( faceIndex ))
850     return 0;
851   return myFaceNodes;
852 }
853
854 //=======================================================================
855 //function : GetFaceNodesIndices
856 //purpose  : Return pointer to the array of face nodes indices
857 //           To comfort link iteration, the array
858 //           length == NbFaceNodes( faceIndex ) + 1 and
859 //           the last node index == the first one.
860 //=======================================================================
861
862 const int* SMDS_VolumeTool::GetFaceNodesIndices( int faceIndex )
863 {
864   if (myVolume->IsPoly()) {
865     MESSAGE("Warning: attempt to obtain FaceNodesIndices of polyhedral volume");
866     return NULL;
867   }
868   if ( !setFace( faceIndex ))
869     return 0;
870   return myFaceNodeIndices;
871 }
872
873 //=======================================================================
874 //function : GetFaceNodes
875 //purpose  : Return a set of face nodes.
876 //=======================================================================
877
878 bool SMDS_VolumeTool::GetFaceNodes (int                        faceIndex,
879                                     set<const SMDS_MeshNode*>& theFaceNodes )
880 {
881   if ( !setFace( faceIndex ))
882     return false;
883
884   theFaceNodes.clear();
885   int iNode, nbNode = myFaceNbNodes;
886   for ( iNode = 0; iNode < nbNode; iNode++ )
887     theFaceNodes.insert( myFaceNodes[ iNode ]);
888
889   return true;
890 }
891
892 //=======================================================================
893 //function : IsFaceExternal
894 //purpose  : Check normal orientation of a returned face
895 //=======================================================================
896
897 bool SMDS_VolumeTool::IsFaceExternal( int faceIndex )
898 {
899   if ( myExternalFaces || !myVolume )
900     return true;
901
902   if (myVolume->IsPoly()) {
903     XYZ aNormal, baryCenter, p0 (myPolyedre->GetFaceNode(faceIndex + 1, 1));
904     GetFaceNormal(faceIndex, aNormal.x, aNormal.y, aNormal.z);
905     GetBaryCenter(baryCenter.x, baryCenter.y, baryCenter.z);
906     XYZ insideVec (baryCenter - p0);
907     if (insideVec.Dot(aNormal) > 0)
908       return false;
909     return true;
910   }
911
912   switch ( myVolumeNbNodes ) {
913   case 4:
914   case 5:
915   case 10:
916   case 13:
917     // only the bottom of a reversed tetrahedron can be internal
918     return ( myVolForward || faceIndex != 0 );
919   case 6:
920   case 15:
921     // in a forward pentahedron, the top is internal, in a reversed one - bottom
922     return ( myVolForward ? faceIndex != 1 : faceIndex != 0 );
923   case 8:
924   case 20: {
925     // in a forward hexahedron, even face normal is external, odd - internal
926     bool odd = faceIndex % 2;
927     return ( myVolForward ? !odd : odd );
928   }
929   default:;
930   }
931   return false;
932 }
933
934 //=======================================================================
935 //function : GetFaceNormal
936 //purpose  : Return a normal to a face
937 //=======================================================================
938
939 bool SMDS_VolumeTool::GetFaceNormal (int faceIndex, double & X, double & Y, double & Z)
940 {
941   if ( !setFace( faceIndex ))
942     return false;
943
944   XYZ p1 ( myFaceNodes[0] );
945   XYZ p2 ( myFaceNodes[1] );
946   XYZ p3 ( myFaceNodes[2] );
947   XYZ aVec12( p2 - p1 );
948   XYZ aVec13( p3 - p1 );
949   XYZ cross = aVec12.Crossed( aVec13 );
950
951   if ( myFaceNbNodes == 4 ) {
952     XYZ p4 ( myFaceNodes[3] );
953     XYZ aVec14( p4 - p1 );
954     XYZ cross2 = aVec13.Crossed( aVec14 );
955     cross.x += cross2.x;
956     cross.y += cross2.y;
957     cross.z += cross2.z;    
958   }
959
960   double size = cross.Magnitude();
961   if ( size <= DBL_MIN )
962     return false;
963
964   X = cross.x / size;
965   Y = cross.y / size;
966   Z = cross.z / size;
967
968   return true;
969 }
970
971 //=======================================================================
972 //function : GetFaceArea
973 //purpose  : Return face area
974 //=======================================================================
975
976 double SMDS_VolumeTool::GetFaceArea( int faceIndex )
977 {
978   if (myVolume->IsPoly()) {
979     MESSAGE("Warning: attempt to obtain area of a face of polyhedral volume");
980     return 0;
981   }
982
983   if ( !setFace( faceIndex ))
984     return 0;
985
986   XYZ p1 ( myFaceNodes[0] );
987   XYZ p2 ( myFaceNodes[1] );
988   XYZ p3 ( myFaceNodes[2] );
989   XYZ aVec12( p2 - p1 );
990   XYZ aVec13( p3 - p1 );
991   double area = aVec12.Crossed( aVec13 ).Magnitude() * 0.5;
992
993   if ( myFaceNbNodes == 4 ) {
994     XYZ p4 ( myFaceNodes[3] );
995     XYZ aVec14( p4 - p1 );
996     area += aVec14.Crossed( aVec13 ).Magnitude() * 0.5;
997   }
998   return area;
999 }
1000
1001 //=======================================================================
1002 //function : GetOppFaceIndex
1003 //purpose  : Return index of the opposite face if it exists, else -1.
1004 //=======================================================================
1005
1006 int SMDS_VolumeTool::GetOppFaceIndex( int faceIndex ) const
1007 {
1008   int ind = -1;
1009   if (myVolume->IsPoly()) {
1010     MESSAGE("Warning: attempt to obtain opposite face on polyhedral volume");
1011     return ind;
1012   }
1013
1014   if ( faceIndex >= 0 && faceIndex < NbFaces() ) {
1015     switch ( myVolumeNbNodes ) {
1016     case 6:
1017       if ( faceIndex == 0 || faceIndex == 1 )
1018         ind = 1 - faceIndex;
1019         break;
1020     case 8:
1021       ind = faceIndex + ( faceIndex % 2 ? -1 : 1 );
1022       break;
1023     default:;
1024     }
1025   }
1026   return ind;
1027 }
1028
1029 //=======================================================================
1030 //function : IsLinked
1031 //purpose  : return true if theNode1 is linked with theNode2
1032 //=======================================================================
1033
1034 bool SMDS_VolumeTool::IsLinked (const SMDS_MeshNode* theNode1,
1035                                 const SMDS_MeshNode* theNode2) const
1036 {
1037   if ( !myVolume )
1038     return false;
1039
1040   if (myVolume->IsPoly()) {
1041     if (!myPolyedre) {
1042       MESSAGE("Warning: bad volumic element");
1043       return false;
1044     }
1045     bool isLinked = false;
1046     int iface;
1047     for (iface = 1; iface <= myNbFaces && !isLinked; iface++) {
1048       int inode, nbFaceNodes = myPolyedre->NbFaceNodes(iface);
1049
1050       for (inode = 1; inode <= nbFaceNodes && !isLinked; inode++) {
1051         const SMDS_MeshNode* curNode = myPolyedre->GetFaceNode(iface, inode);
1052
1053         if (curNode == theNode1 || curNode == theNode2) {
1054           int inextnode = (inode == nbFaceNodes) ? 1 : inode + 1;
1055           const SMDS_MeshNode* nextNode = myPolyedre->GetFaceNode(iface, inextnode);
1056
1057           if ((curNode == theNode1 && nextNode == theNode2) ||
1058               (curNode == theNode2 && nextNode == theNode1)) {
1059             isLinked = true;
1060           }
1061         }
1062       }
1063     }
1064     return isLinked;
1065   }
1066
1067   // find nodes indices
1068   int i1 = -1, i2 = -1;
1069   for ( int i = 0; i < myVolumeNbNodes; i++ ) {
1070     if ( myVolumeNodes[ i ] == theNode1 )
1071       i1 = i;
1072     else if ( myVolumeNodes[ i ] == theNode2 )
1073       i2 = i;
1074   }
1075   return IsLinked( i1, i2 );
1076 }
1077
1078 //=======================================================================
1079 //function : IsLinked
1080 //purpose  : return true if the node with theNode1Index is linked
1081 //           with the node with theNode2Index
1082 //=======================================================================
1083
1084 bool SMDS_VolumeTool::IsLinked (const int theNode1Index,
1085                                 const int theNode2Index) const
1086 {
1087   if (myVolume->IsPoly()) {
1088     return IsLinked(myVolumeNodes[theNode1Index], myVolumeNodes[theNode2Index]);
1089   }
1090
1091   int minInd = theNode1Index < theNode2Index ? theNode1Index : theNode2Index;
1092   int maxInd = theNode1Index < theNode2Index ? theNode2Index : theNode1Index;
1093
1094   if ( minInd < 0 || maxInd > myVolumeNbNodes - 1 || maxInd == minInd )
1095     return false;
1096
1097   switch ( myVolumeNbNodes ) {
1098   case 4:
1099     return true;
1100   case 5:
1101     if ( maxInd == 4 )
1102       return true;
1103     switch ( maxInd - minInd ) {
1104     case 1:
1105     case 3: return true;
1106     default:;
1107     }
1108     break;
1109   case 6:
1110     switch ( maxInd - minInd ) {
1111     case 1: return minInd != 2;
1112     case 2: return minInd == 0 || minInd == 3;
1113     case 3: return true;
1114     default:;
1115     }
1116     break;
1117   case 8:
1118     switch ( maxInd - minInd ) {
1119     case 1: return minInd != 3;
1120     case 3: return minInd == 0 || minInd == 4;
1121     case 4: return true;
1122     default:;
1123     }
1124     break;
1125   default:;
1126   }
1127   return false;
1128 }
1129
1130 //=======================================================================
1131 //function : GetNodeIndex
1132 //purpose  : Return an index of theNode
1133 //=======================================================================
1134
1135 int SMDS_VolumeTool::GetNodeIndex(const SMDS_MeshNode* theNode) const
1136 {
1137   if ( myVolume ) {
1138     for ( int i = 0; i < myVolumeNbNodes; i++ ) {
1139       if ( myVolumeNodes[ i ] == theNode )
1140         return i;
1141     }
1142   }
1143   return -1;
1144 }
1145
1146 //=======================================================================
1147 //function : IsFreeFace
1148 //purpose  : check that only one volume is build on the face nodes
1149 //=======================================================================
1150
1151 bool SMDS_VolumeTool::IsFreeFace( int faceIndex )
1152 {
1153   const int free = true;
1154
1155   if (!setFace( faceIndex ))
1156     return !free;
1157
1158   const SMDS_MeshNode** nodes = GetFaceNodes( faceIndex );
1159   int nbFaceNodes = myFaceNbNodes;
1160
1161   // evaluate nb of face nodes shared by other volume
1162   int maxNbShared = -1;
1163   typedef map< const SMDS_MeshElement*, int > TElemIntMap;
1164   TElemIntMap volNbShared;
1165   TElemIntMap::iterator vNbIt;
1166   for ( int iNode = 0; iNode < nbFaceNodes; iNode++ )
1167   {
1168     const SMDS_MeshNode* n = nodes[ iNode ];
1169     SMDS_ElemIteratorPtr eIt = n->GetInverseElementIterator();
1170     while ( eIt->more() ) {
1171       const SMDS_MeshElement* elem = eIt->next();
1172       if ( elem != myVolume && elem->GetType() == SMDSAbs_Volume ) {
1173         int nbShared = 1;
1174         vNbIt = volNbShared.find( elem );
1175         if ( vNbIt == volNbShared.end() )
1176           volNbShared.insert ( TElemIntMap::value_type( elem, nbShared ));
1177         else
1178           nbShared = ++(*vNbIt).second;
1179         if ( nbShared > maxNbShared )
1180           maxNbShared = nbShared;
1181       }
1182     }
1183   }
1184   if ( maxNbShared < 3 )
1185     return free; // is free
1186
1187   // find volumes laying on the opposite side of the face
1188   // and sharing all nodes
1189   XYZ intNormal; // internal normal
1190   GetFaceNormal( faceIndex, intNormal.x, intNormal.y, intNormal.z );
1191   if ( IsFaceExternal( faceIndex ))
1192     intNormal = XYZ( -intNormal.x, -intNormal.y, -intNormal.z );
1193   XYZ p0 ( nodes[0] ), baryCenter;
1194   for ( vNbIt = volNbShared.begin(); vNbIt != volNbShared.end(); vNbIt++ )
1195   {
1196     int nbShared = (*vNbIt).second;
1197     if ( nbShared >= 3 ) {
1198       SMDS_VolumeTool volume( (*vNbIt).first );
1199       volume.GetBaryCenter( baryCenter.x, baryCenter.y, baryCenter.z );
1200       XYZ intNormal2( baryCenter - p0 );
1201       if ( intNormal.Dot( intNormal2 ) < 0 )
1202         continue; // opposite side
1203     }
1204     // remove a volume from volNbShared map
1205     volNbShared.erase( vNbIt );
1206   }
1207   // here volNbShared contains only volumes laying on the
1208   // opposite side of the face
1209   if ( volNbShared.empty() )
1210     return free; // is free
1211
1212   // check if the whole area of a face is shared
1213   bool isShared[] = { false, false, false, false }; // 4 triangle parts of a quadrangle
1214   for ( vNbIt = volNbShared.begin(); vNbIt != volNbShared.end(); vNbIt++ )
1215   {
1216     SMDS_VolumeTool volume( (*vNbIt).first );
1217     bool prevLinkShared = false;
1218     int nbSharedLinks = 0;
1219     for ( int iNode = 0; iNode < nbFaceNodes; iNode++ )
1220     {
1221       bool linkShared = volume.IsLinked( nodes[ iNode ], nodes[ iNode + 1] );
1222       if ( linkShared )
1223         nbSharedLinks++;
1224       if ( linkShared && prevLinkShared &&
1225           volume.IsLinked( nodes[ iNode - 1 ], nodes[ iNode + 1] ))
1226         isShared[ iNode ] = true;
1227       prevLinkShared = linkShared;
1228     }
1229     if ( nbSharedLinks == nbFaceNodes )
1230       return !free; // is not free
1231     if ( nbFaceNodes == 4 ) {
1232       // check traingle parts 1 & 3
1233       if ( isShared[1] && isShared[3] )
1234         return !free; // is not free
1235       // check triangle parts 0 & 2;
1236       // 0 part could not be checked in the loop; check it here
1237       if ( isShared[2] && prevLinkShared &&
1238           volume.IsLinked( nodes[ 0 ], nodes[ 1 ] ) &&
1239           volume.IsLinked( nodes[ 1 ], nodes[ 3 ] ) )
1240         return !free; // is not free
1241     }
1242   }
1243   return free;
1244 }
1245
1246 //=======================================================================
1247 //function : GetFaceIndex
1248 //purpose  : Return index of a face formed by theFaceNodes
1249 //=======================================================================
1250
1251 int SMDS_VolumeTool::GetFaceIndex( const set<const SMDS_MeshNode*>& theFaceNodes )
1252 {
1253   for ( int iFace = 0; iFace < myNbFaces; iFace++ ) {
1254     const SMDS_MeshNode** nodes = GetFaceNodes( iFace );
1255     int nbFaceNodes = NbFaceNodes( iFace );
1256     set<const SMDS_MeshNode*> nodeSet;
1257     for ( int iNode = 0; iNode < nbFaceNodes; iNode++ )
1258       nodeSet.insert( nodes[ iNode ] );
1259     if ( theFaceNodes == nodeSet )
1260       return iFace;
1261   }
1262   return -1;
1263 }
1264
1265 //=======================================================================
1266 //function : GetFaceIndex
1267 //purpose  : Return index of a face formed by theFaceNodes
1268 //=======================================================================
1269
1270 /*int SMDS_VolumeTool::GetFaceIndex( const set<int>& theFaceNodesIndices )
1271 {
1272   for ( int iFace = 0; iFace < myNbFaces; iFace++ ) {
1273     const int* nodes = GetFaceNodesIndices( iFace );
1274     int nbFaceNodes = NbFaceNodes( iFace );
1275     set<int> nodeSet;
1276     for ( int iNode = 0; iNode < nbFaceNodes; iNode++ )
1277       nodeSet.insert( nodes[ iNode ] );
1278     if ( theFaceNodesIndices == nodeSet )
1279       return iFace;
1280   }
1281   return -1;
1282 }*/
1283
1284 //=======================================================================
1285 //function : setFace
1286 //purpose  : 
1287 //=======================================================================
1288
1289 bool SMDS_VolumeTool::setFace( int faceIndex )
1290 {
1291   if ( !myVolume )
1292     return false;
1293
1294   if ( myCurFace == faceIndex )
1295     return true;
1296
1297   myCurFace = -1;
1298
1299   if ( faceIndex < 0 || faceIndex >= NbFaces() )
1300     return false;
1301
1302   if (myFaceNodes != NULL) {
1303     delete [] myFaceNodes;
1304     myFaceNodes = NULL;
1305   }
1306
1307   if (myVolume->IsPoly()) {
1308     if (!myPolyedre) {
1309       MESSAGE("Warning: bad volumic element");
1310       return false;
1311     }
1312
1313     // check orientation
1314     bool isGoodOri = true;
1315     if (myExternalFaces)
1316       isGoodOri = IsFaceExternal( faceIndex );
1317
1318     // set face nodes
1319     int iNode;
1320     myFaceNbNodes = myPolyedre->NbFaceNodes(faceIndex + 1);
1321     myFaceNodes = new const SMDS_MeshNode* [myFaceNbNodes + 1];
1322     if (isGoodOri) {
1323       for ( iNode = 0; iNode < myFaceNbNodes; iNode++ )
1324         myFaceNodes[ iNode ] = myPolyedre->GetFaceNode(faceIndex + 1, iNode + 1);
1325     } else {
1326       for ( iNode = 0; iNode < myFaceNbNodes; iNode++ )
1327         myFaceNodes[ iNode ] = myPolyedre->GetFaceNode(faceIndex + 1, myFaceNbNodes - iNode);
1328     }
1329     myFaceNodes[ myFaceNbNodes ] = myFaceNodes[ 0 ]; // last = first
1330
1331   }
1332   else {
1333     // choose face node indices
1334     switch ( myVolumeNbNodes ) {
1335     case 4:
1336       myFaceNbNodes = Tetra_nbN[ faceIndex ];
1337       if ( myExternalFaces )
1338         myFaceNodeIndices = myVolForward ? Tetra_F[ faceIndex ] : Tetra_RE[ faceIndex ];
1339       else
1340         myFaceNodeIndices = myVolForward ? Tetra_F[ faceIndex ] : Tetra_R[ faceIndex ];
1341       break;
1342     case 5:
1343       myFaceNbNodes = Pyramid_nbN[ faceIndex ];
1344       if ( myExternalFaces )
1345         myFaceNodeIndices = myVolForward ? Pyramid_F[ faceIndex ] : Pyramid_RE[ faceIndex ];
1346       else
1347         myFaceNodeIndices = myVolForward ? Pyramid_F[ faceIndex ] : Pyramid_R[ faceIndex ];
1348       break;
1349     case 6:
1350       myFaceNbNodes = Penta_nbN[ faceIndex ];
1351       if ( myExternalFaces )
1352         myFaceNodeIndices = myVolForward ? Penta_FE[ faceIndex ] : Penta_RE[ faceIndex ];
1353       else
1354         myFaceNodeIndices = myVolForward ? Penta_F[ faceIndex ] : Penta_R[ faceIndex ];
1355       break;
1356     case 8:
1357       myFaceNbNodes = Hexa_nbN[ faceIndex ];
1358       if ( myExternalFaces )
1359         myFaceNodeIndices = myVolForward ? Hexa_FE[ faceIndex ] : Hexa_RE[ faceIndex ];
1360       else
1361         myFaceNodeIndices = Hexa_F[ faceIndex ];
1362       break;
1363     case 10:
1364       myFaceNbNodes = QuadTetra_nbN[ faceIndex ];
1365       if ( myExternalFaces )
1366         myFaceNodeIndices = myVolForward ? QuadTetra_F[ faceIndex ] : QuadTetra_RE[ faceIndex ];
1367       else
1368         myFaceNodeIndices = myVolForward ? QuadTetra_F[ faceIndex ] : QuadTetra_R[ faceIndex ];
1369       break;
1370     case 13:
1371       myFaceNbNodes = QuadPyram_nbN[ faceIndex ];
1372       if ( myExternalFaces )
1373         myFaceNodeIndices = myVolForward ? QuadPyram_F[ faceIndex ] : QuadPyram_RE[ faceIndex ];
1374       else
1375         myFaceNodeIndices = myVolForward ? QuadPyram_F[ faceIndex ] : QuadPyram_R[ faceIndex ];
1376       break;
1377     case 15:
1378       myFaceNbNodes = QuadPenta_nbN[ faceIndex ];
1379       if ( myExternalFaces )
1380         myFaceNodeIndices = myVolForward ? QuadPenta_FE[ faceIndex ] : QuadPenta_RE[ faceIndex ];
1381       else
1382         myFaceNodeIndices = myVolForward ? QuadPenta_F[ faceIndex ] : QuadPenta_R[ faceIndex ];
1383       break;
1384     case 20:
1385       myFaceNbNodes = QuadHexa_nbN[ faceIndex ];
1386       if ( myExternalFaces )
1387         myFaceNodeIndices = myVolForward ? QuadHexa_FE[ faceIndex ] : QuadHexa_RE[ faceIndex ];
1388       else
1389         myFaceNodeIndices = QuadHexa_F[ faceIndex ];
1390       break;
1391     default:
1392       return false;
1393     }
1394
1395     // set face nodes
1396     myFaceNodes = new const SMDS_MeshNode* [myFaceNbNodes + 1];
1397     for ( int iNode = 0; iNode < myFaceNbNodes; iNode++ )
1398       myFaceNodes[ iNode ] = myVolumeNodes[ myFaceNodeIndices[ iNode ]];
1399     myFaceNodes[ myFaceNbNodes ] = myFaceNodes[ 0 ];
1400   }
1401
1402   myCurFace = faceIndex;
1403
1404   return true;
1405 }
1406
1407 //=======================================================================
1408 //function : GetType
1409 //purpose  : return VolumeType by nb of nodes in a volume
1410 //=======================================================================
1411
1412 SMDS_VolumeTool::VolumeType SMDS_VolumeTool::GetType(int nbNodes)
1413 {
1414   switch ( nbNodes ) {
1415   case 4: return TETRA;
1416   case 5: return PYRAM;
1417   case 6: return PENTA;
1418   case 8: return HEXA;
1419   case 10: return QUAD_TETRA;
1420   case 13: return QUAD_PYRAM;
1421   case 15: return QUAD_PENTA;
1422   case 20: return QUAD_HEXA;
1423   default:return UNKNOWN;
1424   }
1425 }
1426
1427 //=======================================================================
1428 //function : NbFaces
1429 //purpose  : return nb of faces by volume type
1430 //=======================================================================
1431
1432 int SMDS_VolumeTool::NbFaces( VolumeType type )
1433 {
1434   switch ( type ) {
1435   case TETRA     :
1436   case QUAD_TETRA: return 4;
1437   case PYRAM     :
1438   case QUAD_PYRAM: return 5;
1439   case PENTA     :
1440   case QUAD_PENTA: return 5;
1441   case HEXA      :
1442   case QUAD_HEXA : return 6;
1443   default:    return 0;
1444   }
1445 }
1446
1447 //=======================================================================
1448 //function : GetFaceNodesIndices
1449 //purpose  : Return the array of face nodes indices
1450 //           To comfort link iteration, the array
1451 //           length == NbFaceNodes( faceIndex ) + 1 and
1452 //           the last node index == the first one.
1453 //=======================================================================
1454
1455 const int* SMDS_VolumeTool::GetFaceNodesIndices(VolumeType type,
1456                                                 int        faceIndex,
1457                                                 bool       external)
1458 {
1459   switch ( type ) {
1460   case TETRA: return Tetra_F[ faceIndex ];
1461   case PYRAM: return Pyramid_F[ faceIndex ];
1462   case PENTA: return external ? Penta_FE[ faceIndex ] : Penta_F[ faceIndex ];
1463   case HEXA:  return external ? Hexa_FE[ faceIndex ] : Hexa_F[ faceIndex ];
1464   case QUAD_TETRA: return QuadTetra_F[ faceIndex ];
1465   case QUAD_PYRAM: return QuadPyram_F[ faceIndex ];
1466   case QUAD_PENTA: return external ? QuadPenta_FE[ faceIndex ] : QuadPenta_F[ faceIndex ];
1467   case QUAD_HEXA:  return external ? QuadHexa_FE[ faceIndex ] : QuadHexa_F[ faceIndex ];
1468   default:;
1469   }
1470   return 0;
1471 }
1472
1473 //=======================================================================
1474 //function : NbFaceNodes
1475 //purpose  : Return number of nodes in the array of face nodes
1476 //=======================================================================
1477
1478 int SMDS_VolumeTool::NbFaceNodes(VolumeType type,
1479                                  int        faceIndex )
1480 {
1481   switch ( type ) {
1482   case TETRA: return Tetra_nbN[ faceIndex ];
1483   case PYRAM: return Pyramid_nbN[ faceIndex ];
1484   case PENTA: return Penta_nbN[ faceIndex ];
1485   case HEXA:  return Hexa_nbN[ faceIndex ];
1486   case QUAD_TETRA: return QuadTetra_nbN[ faceIndex ];
1487   case QUAD_PYRAM: return QuadPyram_nbN[ faceIndex ];
1488   case QUAD_PENTA: return QuadPenta_nbN[ faceIndex ];
1489   case QUAD_HEXA:  return QuadHexa_nbN[ faceIndex ];
1490   default:;
1491   }
1492   return 0;
1493 }
1494