Back to index

salome-smesh  6.5.0
SMDS_VolumeTool.cxx
Go to the documentation of this file.
00001 // Copyright (C) 2007-2012  CEA/DEN, EDF R&D, OPEN CASCADE
00002 //
00003 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
00004 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
00005 //
00006 // This library is free software; you can redistribute it and/or
00007 // modify it under the terms of the GNU Lesser General Public
00008 // License as published by the Free Software Foundation; either
00009 // version 2.1 of the License.
00010 //
00011 // This library is distributed in the hope that it will be useful,
00012 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014 // Lesser General Public License for more details.
00015 //
00016 // You should have received a copy of the GNU Lesser General Public
00017 // License along with this library; if not, write to the Free Software
00018 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
00019 //
00020 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
00021 //
00022 
00023 // File      : SMDS_VolumeTool.cxx
00024 // Created   : Tue Jul 13 12:22:13 2004
00025 // Author    : Edward AGAPOV (eap)
00026 //
00027 #ifdef _MSC_VER
00028 #pragma warning(disable:4786)
00029 #endif
00030 
00031 #include "SMDS_VolumeTool.hxx"
00032 
00033 #include "SMDS_MeshElement.hxx"
00034 #include "SMDS_MeshNode.hxx"
00035 #include "SMDS_VtkVolume.hxx"
00036 #include "SMDS_Mesh.hxx"
00037 
00038 #include "utilities.h"
00039 
00040 #include <map>
00041 #include <limits>
00042 #include <cmath>
00043 
00044 using namespace std;
00045 
00046 // ======================================================
00047 // Node indices in faces depending on volume orientation
00048 // making most faces normals external
00049 // ======================================================
00050 // For all elements, 0-th face is bottom based on the first nodes.
00051 // For prismatic elements (tetra,hexa,prisms), 1-th face is a top one.
00052 // For all elements, side faces follow order of bottom nodes
00053 // ======================================================
00054 
00055 /*
00056 //           N3
00057 //           +
00058 //          /|\
00059 //         / | \
00060 //        /  |  \
00061 //    N0 +---|---+ N1                TETRAHEDRON
00062 //       \   |   /
00063 //        \  |  /
00064 //         \ | /
00065 //          \|/
00066 //           +
00067 //           N2
00068 */
00069 static int Tetra_F [4][4] = { // FORWARD == EXTERNAL
00070   { 0, 1, 2, 0 },              // All faces have external normals
00071   { 0, 3, 1, 0 },
00072   { 1, 3, 2, 1 },
00073   { 0, 2, 3, 0 }}; 
00074 static int Tetra_RE [4][4] = { // REVERSED -> FORWARD (EXTERNAL)
00075   { 0, 2, 1, 0 },              // All faces have external normals
00076   { 0, 1, 3, 0 },
00077   { 1, 2, 3, 1 },
00078   { 0, 3, 2, 0 }};
00079 static int Tetra_nbN [] = { 3, 3, 3, 3 };
00080 
00081 //
00082 //     PYRAMID
00083 //
00084 static int Pyramid_F [5][5] = { // FORWARD == EXTERNAL
00085   { 0, 1, 2, 3, 0 },            // All faces have external normals
00086   { 0, 4, 1, 0, 4 },
00087   { 1, 4, 2, 1, 4 },
00088   { 2, 4, 3, 2, 4 },
00089   { 3, 4, 0, 3, 4 }
00090 }; 
00091 static int Pyramid_RE [5][5] = { // REVERSED -> FORWARD (EXTERNAL)
00092   { 0, 3, 2, 1, 0 },             // All faces but a bottom have external normals
00093   { 0, 1, 4, 0, 4 },
00094   { 1, 2, 4, 1, 4 },
00095   { 2, 3, 4, 2, 4 },
00096   { 3, 0, 4, 3, 4 }}; 
00097 static int Pyramid_nbN [] = { 4, 3, 3, 3, 3 };
00098 
00099 /*   
00100 //            + N4
00101 //           /|\
00102 //          / | \
00103 //         /  |  \
00104 //        /   |   \
00105 //    N3 +---------+ N5
00106 //       |    |    |
00107 //       |    + N1 |
00108 //       |   / \   |                PENTAHEDRON
00109 //       |  /   \  |
00110 //       | /     \ |
00111 //       |/       \|
00112 //    N0 +---------+ N2
00113 */
00114 static int Penta_F [5][5] = { // FORWARD
00115   { 0, 1, 2, 0, 0 },          // All faces have external normals
00116   { 3, 5, 4, 3, 3 },          // 0 is bottom, 1 is top face
00117   { 0, 3, 4, 1, 0 },
00118   { 1, 4, 5, 2, 1 },
00119   { 0, 2, 5, 3, 0 }}; 
00120 static int Penta_RE [5][5] = { // REVERSED -> EXTERNAL
00121   { 0, 2, 1, 0, 0 },
00122   { 3, 4, 5, 3, 3 },
00123   { 0, 1, 4, 3, 0 },
00124   { 1, 2, 5, 4, 1 },
00125   { 0, 3, 5, 2, 0 }}; 
00126 static int Penta_nbN [] = { 3, 3, 4, 4, 4 };
00127 
00128 /*
00129 //         N5+----------+N6
00130 //          /|         /|
00131 //         / |        / |
00132 //        /  |       /  |
00133 //     N4+----------+N7 |
00134 //       |   |      |   |           HEXAHEDRON
00135 //       |   |      |   |
00136 //       |   |      |   |
00137 //       | N1+------|---+N2
00138 //       |  /       |  /
00139 //       | /        | /
00140 //       |/         |/
00141 //     N0+----------+N3
00142 */
00143 static int Hexa_F [6][5] = { // FORWARD
00144   { 0, 1, 2, 3, 0 },
00145   { 4, 7, 6, 5, 4 },          // all face normals are external
00146   { 0, 4, 5, 1, 0 },
00147   { 1, 5, 6, 2, 1 },
00148   { 3, 2, 6, 7, 3 }, 
00149   { 0, 3, 7, 4, 0 }};
00150 static int Hexa_RE [6][5] = { // REVERSED -> EXTERNAL
00151   { 0, 3, 2, 1, 0 },
00152   { 4, 5, 6, 7, 4 },          // all face normals are external
00153   { 0, 1, 5, 4, 0 },
00154   { 1, 2, 6, 5, 1 },
00155   { 3, 7, 6, 2, 3 }, 
00156   { 0, 4, 7, 3, 0 }};
00157 static int Hexa_nbN [] = { 4, 4, 4, 4, 4, 4 };
00158 
00159 /*   
00160 //      N8 +------+ N9
00161 //        /        \
00162 //       /          \
00163 //   N7 +            + N10
00164 //       \          /
00165 //        \        /
00166 //      N6 +------+ N11
00167 //                             HEXAGONAL PRISM
00168 //      N2 +------+ N3
00169 //        /        \
00170 //       /          \
00171 //   N1 +            + N4
00172 //       \          /
00173 //        \        /
00174 //      N0 +------+ N5
00175 */
00176 static int HexPrism_F [8][7] = { // FORWARD
00177   { 0, 1, 2, 3, 4, 5, 0 },
00178   { 6,11,10, 9, 8, 7, 6 },
00179   { 0, 6, 7, 1, 0, 0, 0 },
00180   { 1, 7, 8, 2, 1, 1, 1 },
00181   { 2, 8, 9, 3, 2, 2, 2 },
00182   { 3, 9,10, 4, 3, 3, 3 },
00183   { 4,10,11, 5, 4, 4, 4 },
00184   { 5,11, 6, 0, 5, 5, 5 }}; 
00185 static int HexPrism_RE [8][7] = { // REVERSED -> EXTERNAL
00186   { 0, 5, 4, 3, 2, 1, 0 },
00187   { 6,11,10, 9, 8, 7, 6 },
00188   { 0, 6, 7, 1, 0, 0, 0 },
00189   { 1, 7, 8, 2, 1, 1, 1 },
00190   { 2, 8, 9, 3, 2, 2, 2 },
00191   { 3, 9,10, 4, 3, 3, 3 },
00192   { 4,10,11, 5, 4, 4, 4 },
00193   { 5,11, 6, 0, 5, 5, 5 }}; 
00194 static int HexPrism_nbN [] = { 6, 6, 4, 4, 4, 4, 4, 4 };
00195 
00196 
00197 /*
00198 //           N3
00199 //           +
00200 //          /|\
00201 //        7/ | \8
00202 //        /  |4 \                    QUADRATIC
00203 //    N0 +---|---+ N1                TETRAHEDRON
00204 //       \   +9  /
00205 //        \  |  /
00206 //        6\ | /5
00207 //          \|/
00208 //           +
00209 //           N2
00210 */
00211 static int QuadTetra_F [4][7] = { // FORWARD
00212   { 0, 4, 1, 5, 2, 6, 0 },        // All faces have external normals
00213   { 0, 7, 3, 8, 1, 4, 0 },
00214   { 1, 8, 3, 9, 2, 5, 1 },
00215   { 0, 6, 2, 9, 3, 7, 0 }}; 
00216 static int QuadTetra_RE [4][7] = { // REVERSED -> FORWARD (EXTERNAL)
00217   { 0, 6, 2, 5, 1, 4, 0 },         // All faces have external normals
00218   { 0, 4, 1, 8, 3, 7, 0 },
00219   { 1, 5, 2, 9, 3, 8, 1 },
00220   { 0, 7, 3, 9, 2, 6, 0 }};
00221 static int QuadTetra_nbN [] = { 6, 6, 6, 6 };
00222 
00223 //
00224 //     QUADRATIC
00225 //     PYRAMID
00226 //
00227 //            +4
00228 //
00229 //            
00230 //       10+-----+11
00231 //         |     |        9 - middle point for (0,4) etc.
00232 //         |     |
00233 //        9+-----+12
00234 //
00235 //            6
00236 //      1+----+----+2
00237 //       |         |
00238 //       |         |
00239 //      5+         +7
00240 //       |         |
00241 //       |         |
00242 //      0+----+----+3
00243 //            8
00244 static int QuadPyram_F [5][9] = {  // FORWARD
00245   { 0, 5, 1, 6, 2, 7, 3, 8, 0 },   // All faces have external normals
00246   { 0, 9, 4, 10,1, 5, 0, 4, 4 },
00247   { 1, 10,4, 11,2, 6, 1, 4, 4 },
00248   { 2, 11,4, 12,3, 7, 2, 4, 4 },
00249   { 3, 12,4, 9, 0, 8, 3, 4, 4 }}; 
00250 static int QuadPyram_RE [5][9] = { // REVERSED -> FORWARD (EXTERNAL)
00251   { 0, 8, 3, 7, 2, 6, 1, 5, 0 },   // All faces but a bottom have external normals
00252   { 0, 5, 1, 10,4, 9, 0, 4, 4 },
00253   { 1, 6, 2, 11,4, 10,1, 4, 4 },
00254   { 2, 7, 3, 12,4, 11,2, 4, 4 },
00255   { 3, 8, 0, 9, 4, 12,3, 4, 4 }}; 
00256 static int QuadPyram_nbN [] = { 8, 6, 6, 6, 6 };
00257 
00258 /*   
00259 //            + N4
00260 //           /|\
00261 //         9/ | \10
00262 //         /  |  \
00263 //        /   |   \
00264 //    N3 +----+----+ N5
00265 //       |    |11  |
00266 //       |    |    |
00267 //       |    +13  |                QUADRATIC
00268 //       |    |    |                PENTAHEDRON
00269 //     12+    |    +14
00270 //       |    |    |
00271 //       |    |    |
00272 //       |    + N1 |
00273 //       |   / \   |               
00274 //       | 6/   \7 |
00275 //       | /     \ |
00276 //       |/       \|
00277 //    N0 +---------+ N2
00278 //            8
00279 */
00280 static int QuadPenta_F [5][9] = {  // FORWARD
00281   { 0, 6, 1, 7, 2, 8, 0, 0, 0 },
00282   { 3,11, 5, 10,4, 9, 3, 3, 3 },
00283   { 0, 12,3, 9, 4, 13,1, 6, 0 },
00284   { 1, 13,4, 10,5, 14,2, 7, 1 },
00285   { 0, 8, 2, 14,5, 11,3, 12,0 }}; 
00286 static int QuadPenta_RE [5][9] = { // REVERSED -> EXTERNAL
00287   { 0, 8, 2, 7, 1, 6, 0, 0, 0 },
00288   { 3, 9, 4, 10,5, 11,3, 3, 3 },
00289   { 0, 6, 1, 13,4, 9, 3, 12,0 },
00290   { 1, 7, 2, 14,5, 10,4, 13,1 },
00291   { 0, 12,3, 11,5, 14,2, 8, 0 }}; 
00292 static int QuadPenta_nbN [] = { 6, 6, 8, 8, 8 };
00293 
00294 /*
00295 //                 13
00296 //         N5+-----+-----+N6
00297 //          /|          /|
00298 //       12+ |       14+ |
00299 //        /  |        /  |
00300 //     N4+-----+-----+N7 |           QUADRATIC
00301 //       |   | 15    |   |           HEXAHEDRON
00302 //       |   |       |   |
00303 //       | 17+       |   +18
00304 //       |   |       |   |
00305 //       |   |       |   |
00306 //       |   |       |   |
00307 //     16+   |       +19 |
00308 //       |   |       |   |
00309 //       |   |     9 |   |
00310 //       | N1+-----+-|---+N2
00311 //       |  /        |  /
00312 //       | +8        | +10
00313 //       |/          |/
00314 //     N0+-----+-----+N3
00315 //             11
00316 */
00317 static int QuadHexa_F [6][9] = {  // FORWARD
00318   { 0, 8, 1, 9, 2, 10,3, 11,0 },   // all face normals are external,
00319   { 4, 15,7, 14,6, 13,5, 12,4 },
00320   { 0, 16,4, 12,5, 17,1, 8, 0 },
00321   { 1, 17,5, 13,6, 18,2, 9, 1 },
00322   { 3, 10,2, 18,6, 14,7, 19,3 }, 
00323   { 0, 11,3, 19,7, 15,4, 16,0 }};
00324 static int QuadHexa_RE [6][9] = {  // REVERSED -> EXTERNAL
00325   { 0, 11,3, 10,2, 9, 1, 8, 0 },   // all face normals are external
00326   { 4, 12,5, 13,6, 14,7, 15,4 },
00327   { 0, 8, 1, 17,5, 12,4, 16,0 },
00328   { 1, 9, 2, 18,6, 13,5, 17,1 },
00329   { 3, 19,7, 14,6, 18,2, 10,3 }, 
00330   { 0, 16,4, 15,7, 19,3, 11,0 }};
00331 static int QuadHexa_nbN [] = { 8, 8, 8, 8, 8, 8 };
00332 
00333 static int TriQuadHexa_F [6][9] = {  // FORWARD
00334   { 0, 8, 1, 9, 2, 10,3, 11, 20 },   // all face normals are external
00335   { 4, 15,7, 14,6, 13,5, 12, 25 },
00336   { 0, 16,4, 12,5, 17,1, 8,  21 },
00337   { 1, 17,5, 13,6, 18,2, 9,  22 },
00338   { 3, 10,2, 18,6, 14,7, 19, 23 }, 
00339   { 0, 11,3, 19,7, 15,4, 16, 24 }};
00340 static int TriQuadHexa_RE [6][9] = {  // REVERSED -> EXTERNAL
00341   { 0, 11,3, 10,2, 9, 1, 8,  20 },   // opposite faces are neighbouring,
00342   { 4, 12,5, 13,6, 14,7, 15, 25 },   // all face normals are external
00343   { 0, 8, 1, 17,5, 12,4, 16, 21 },
00344   { 1, 9, 2, 18,6, 13,5, 17, 22 },
00345   { 3, 19,7, 14,6, 18,2, 10, 23 }, 
00346   { 0, 16,4, 15,7, 19,3, 11, 24 }};
00347 static int TriQuadHexa_nbN [] = { 9, 9, 9, 9, 9, 9 };
00348 
00349 
00350 // ========================================================
00351 // to perform some calculations without linkage to CASCADE
00352 // ========================================================
00353 namespace
00354 {
00355 struct XYZ {
00356   double x;
00357   double y;
00358   double z;
00359   XYZ()                               { x = 0; y = 0; z = 0; }
00360   XYZ( double X, double Y, double Z ) { x = X; y = Y; z = Z; }
00361   XYZ( const XYZ& other )             { x = other.x; y = other.y; z = other.z; }
00362   XYZ( const SMDS_MeshNode* n )       { x = n->X(); y = n->Y(); z = n->Z(); }
00363   inline XYZ operator-( const XYZ& other );
00364   inline XYZ operator+( const XYZ& other );
00365   inline XYZ Crossed( const XYZ& other );
00366   inline double Dot( const XYZ& other );
00367   inline double Magnitude();
00368   inline double SquareMagnitude();
00369 };
00370 inline XYZ XYZ::operator-( const XYZ& Right ) {
00371   return XYZ(x - Right.x, y - Right.y, z - Right.z);
00372 }
00373 inline XYZ XYZ::operator+( const XYZ& Right ) {
00374   return XYZ(x + Right.x, y + Right.y, z + Right.z);
00375 }
00376 inline XYZ XYZ::Crossed( const XYZ& Right ) {
00377   return XYZ (y * Right.z - z * Right.y,
00378               z * Right.x - x * Right.z,
00379               x * Right.y - y * Right.x);
00380 }
00381 inline double XYZ::Dot( const XYZ& Other ) {
00382   return(x * Other.x + y * Other.y + z * Other.z);
00383 }
00384 inline double XYZ::Magnitude() {
00385   return sqrt (x * x + y * y + z * z);
00386 }
00387 inline double XYZ::SquareMagnitude() {
00388   return (x * x + y * y + z * z);
00389 }
00390 
00391   //================================================================================
00395   //================================================================================
00396 
00397   SMDS_VolumeTool::VolumeType quadToLinear(SMDS_VolumeTool::VolumeType quadType)
00398   {
00399     SMDS_VolumeTool::VolumeType linType = SMDS_VolumeTool::VolumeType( int(quadType)-4 );
00400     const int nbCornersByQuad = SMDS_VolumeTool::NbCornerNodes( quadType );
00401     if ( SMDS_VolumeTool::NbCornerNodes( linType ) == nbCornersByQuad )
00402       return linType;
00403 
00404     int iLin = 0;
00405     for ( ; iLin < SMDS_VolumeTool::NB_VOLUME_TYPES; ++iLin )
00406       if ( SMDS_VolumeTool::NbCornerNodes( SMDS_VolumeTool::VolumeType( iLin )) == nbCornersByQuad)
00407         return SMDS_VolumeTool::VolumeType( iLin );
00408 
00409     return SMDS_VolumeTool::UNKNOWN;
00410   }
00411 
00412 } // namespace
00413 
00414 //=======================================================================
00415 //function : SMDS_VolumeTool
00416 //purpose  : 
00417 //=======================================================================
00418 
00419 SMDS_VolumeTool::SMDS_VolumeTool ()
00420   : myVolumeNodes( NULL ),
00421     myFaceNodes( NULL )
00422 {
00423   Set( 0 );
00424 }
00425 
00426 //=======================================================================
00427 //function : SMDS_VolumeTool
00428 //purpose  : 
00429 //=======================================================================
00430 
00431 SMDS_VolumeTool::SMDS_VolumeTool (const SMDS_MeshElement* theVolume,
00432                                   const bool              ignoreCentralNodes)
00433   : myVolumeNodes( NULL ),
00434     myFaceNodes( NULL )
00435 {
00436   Set( theVolume, ignoreCentralNodes );
00437 }
00438 
00439 //=======================================================================
00440 //function : SMDS_VolumeTool
00441 //purpose  : 
00442 //=======================================================================
00443 
00444 SMDS_VolumeTool::~SMDS_VolumeTool()
00445 {
00446   if ( myVolumeNodes != NULL ) delete [] myVolumeNodes;
00447   if ( myFaceNodes != NULL   ) delete [] myFaceNodes;
00448 
00449   myFaceNodeIndices = NULL;
00450   myVolumeNodes = myFaceNodes = NULL;
00451 }
00452 
00453 //=======================================================================
00454 //function : SetVolume
00455 //purpose  : Set volume to iterate on
00456 //=======================================================================
00457 
00458 bool SMDS_VolumeTool::Set (const SMDS_MeshElement* theVolume,
00459                            const bool              ignoreCentralNodes)
00460 {
00461   // reset fields
00462   myVolume = 0;
00463   myPolyedre = 0;
00464   myIgnoreCentralNodes = ignoreCentralNodes;
00465 
00466   myVolForward = true;
00467   myNbFaces = 0;
00468   myVolumeNbNodes = 0;
00469   if (myVolumeNodes != NULL) {
00470     delete [] myVolumeNodes;
00471     myVolumeNodes = NULL;
00472   }
00473   myPolyIndices.clear();
00474 
00475   myExternalFaces = false;
00476 
00477   myAllFacesNodeIndices_F  = 0;
00478   //myAllFacesNodeIndices_FE = 0;
00479   myAllFacesNodeIndices_RE = 0;
00480   myAllFacesNbNodes        = 0;
00481 
00482   myCurFace = -1;
00483   myFaceNbNodes = 0;
00484   myFaceNodeIndices = NULL;
00485   if (myFaceNodes != NULL) {
00486     delete [] myFaceNodes;
00487     myFaceNodes = NULL;
00488   }
00489 
00490   // set volume data
00491   if ( !theVolume || theVolume->GetType() != SMDSAbs_Volume )
00492     return false;
00493 
00494   myVolume = theVolume;
00495   if (myVolume->IsPoly())
00496     myPolyedre = dynamic_cast<const SMDS_VtkVolume*>( myVolume );
00497 
00498   myNbFaces = theVolume->NbFaces();
00499   myVolumeNbNodes = theVolume->NbNodes();
00500 
00501   // set nodes
00502   int iNode = 0;
00503   myVolumeNodes = new const SMDS_MeshNode* [myVolumeNbNodes];
00504   SMDS_ElemIteratorPtr nodeIt = myVolume->nodesIterator();
00505   while ( nodeIt->more() )
00506     myVolumeNodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
00507 
00508   // check validity
00509   if ( !setFace(0) )
00510     return ( myVolume = 0 );
00511 
00512   if ( !myPolyedre )
00513   {
00514     // define volume orientation
00515     XYZ botNormal;
00516     GetFaceNormal( 0, botNormal.x, botNormal.y, botNormal.z );
00517     const SMDS_MeshNode* botNode = myVolumeNodes[ 0 ];
00518     int topNodeIndex = myVolume->NbCornerNodes() - 1;
00519     while ( !IsLinked( 0, topNodeIndex, /*ignoreMediumNodes=*/true )) --topNodeIndex;
00520     const SMDS_MeshNode* topNode = myVolumeNodes[ topNodeIndex ];
00521     XYZ upDir (topNode->X() - botNode->X(),
00522                topNode->Y() - botNode->Y(),
00523                topNode->Z() - botNode->Z() );
00524     myVolForward = ( botNormal.Dot( upDir ) < 0 );
00525 
00526     if ( !myVolForward )
00527       myCurFace = -1; // previous setFace(0) didn't take myVolForward into account
00528   }
00529   return true;
00530 }
00531 
00532 //=======================================================================
00533 //function : Inverse
00534 //purpose  : Inverse volume
00535 //=======================================================================
00536 
00537 #define SWAP_NODES(nodes,i1,i2)           \
00538 {                                         \
00539   const SMDS_MeshNode* tmp = nodes[ i1 ]; \
00540   nodes[ i1 ] = nodes[ i2 ];              \
00541   nodes[ i2 ] = tmp;                      \
00542 }
00543 void SMDS_VolumeTool::Inverse ()
00544 {
00545   if ( !myVolume ) return;
00546 
00547   if (myVolume->IsPoly()) {
00548     MESSAGE("Warning: attempt to inverse polyhedral volume");
00549     return;
00550   }
00551 
00552   myVolForward = !myVolForward;
00553   myCurFace = -1;
00554 
00555   // inverse top and bottom faces
00556   switch ( myVolumeNbNodes ) {
00557   case 4:
00558     SWAP_NODES( myVolumeNodes, 1, 2 );
00559     break;
00560   case 5:
00561     SWAP_NODES( myVolumeNodes, 1, 3 );
00562     break;
00563   case 6:
00564     SWAP_NODES( myVolumeNodes, 1, 2 );
00565     SWAP_NODES( myVolumeNodes, 4, 5 );
00566     break;
00567   case 8:
00568     SWAP_NODES( myVolumeNodes, 1, 3 );
00569     SWAP_NODES( myVolumeNodes, 5, 7 );
00570     break;
00571   case 12:
00572     SWAP_NODES( myVolumeNodes, 1, 5 );
00573     SWAP_NODES( myVolumeNodes, 2, 4 );
00574     SWAP_NODES( myVolumeNodes, 7, 11 );
00575     SWAP_NODES( myVolumeNodes, 8, 10 );
00576     break;
00577 
00578   case 10:
00579     SWAP_NODES( myVolumeNodes, 1, 2 );
00580     SWAP_NODES( myVolumeNodes, 4, 6 );
00581     SWAP_NODES( myVolumeNodes, 8, 9 );
00582     break;
00583   case 13:
00584     SWAP_NODES( myVolumeNodes, 1, 3 );
00585     SWAP_NODES( myVolumeNodes, 5, 8 );
00586     SWAP_NODES( myVolumeNodes, 6, 7 );
00587     SWAP_NODES( myVolumeNodes, 10, 12 );
00588     break;
00589   case 15:
00590     SWAP_NODES( myVolumeNodes, 1, 2 );
00591     SWAP_NODES( myVolumeNodes, 4, 5 );
00592     SWAP_NODES( myVolumeNodes, 6, 8 );
00593     SWAP_NODES( myVolumeNodes, 9, 11 );
00594     SWAP_NODES( myVolumeNodes, 13, 14 );
00595     break;
00596   case 20:
00597     SWAP_NODES( myVolumeNodes, 1, 3 );
00598     SWAP_NODES( myVolumeNodes, 5, 7 );
00599     SWAP_NODES( myVolumeNodes, 8, 11 );
00600     SWAP_NODES( myVolumeNodes, 9, 10 );
00601     SWAP_NODES( myVolumeNodes, 12, 15 );
00602     SWAP_NODES( myVolumeNodes, 13, 14 );
00603     SWAP_NODES( myVolumeNodes, 17, 19 );
00604     break;
00605   case 27:
00606     SWAP_NODES( myVolumeNodes, 1, 3 );
00607     SWAP_NODES( myVolumeNodes, 5, 7 );
00608     SWAP_NODES( myVolumeNodes, 8, 11 );
00609     SWAP_NODES( myVolumeNodes, 9, 10 );
00610     SWAP_NODES( myVolumeNodes, 12, 15 );
00611     SWAP_NODES( myVolumeNodes, 13, 14 );
00612     SWAP_NODES( myVolumeNodes, 17, 19 );
00613     SWAP_NODES( myVolumeNodes, 21, 24 );
00614     SWAP_NODES( myVolumeNodes, 22, 23 );
00615     break;
00616   default:;
00617   }
00618 }
00619 
00620 //=======================================================================
00621 //function : GetVolumeType
00622 //purpose  : 
00623 //=======================================================================
00624 
00625 SMDS_VolumeTool::VolumeType SMDS_VolumeTool::GetVolumeType() const
00626 {
00627   if ( myPolyedre )
00628     return POLYHEDA;
00629 
00630   switch( myVolumeNbNodes ) {
00631   case 4: return TETRA;
00632   case 5: return PYRAM;
00633   case 6: return PENTA;
00634   case 8: return HEXA;
00635   case 12: return HEX_PRISM;
00636   case 10: return QUAD_TETRA;
00637   case 13: return QUAD_PYRAM;
00638   case 15: return QUAD_PENTA;
00639   case 20: return QUAD_HEXA;
00640   case 27: return QUAD_HEXA;
00641   default: break;
00642   }
00643 
00644   return UNKNOWN;
00645 }
00646 
00647 //=======================================================================
00648 //function : getTetraVolume
00649 //purpose  : 
00650 //=======================================================================
00651 
00652 static double getTetraVolume(const SMDS_MeshNode* n1,
00653                              const SMDS_MeshNode* n2,
00654                              const SMDS_MeshNode* n3,
00655                              const SMDS_MeshNode* n4)
00656 {
00657   double X1 = n1->X();
00658   double Y1 = n1->Y();
00659   double Z1 = n1->Z();
00660 
00661   double X2 = n2->X();
00662   double Y2 = n2->Y();
00663   double Z2 = n2->Z();
00664 
00665   double X3 = n3->X();
00666   double Y3 = n3->Y();
00667   double Z3 = n3->Z();
00668 
00669   double X4 = n4->X();
00670   double Y4 = n4->Y();
00671   double Z4 = n4->Z();
00672 
00673   double Q1 = -(X1-X2)*(Y3*Z4-Y4*Z3);
00674   double Q2 =  (X1-X3)*(Y2*Z4-Y4*Z2);
00675   double R1 = -(X1-X4)*(Y2*Z3-Y3*Z2);
00676   double R2 = -(X2-X3)*(Y1*Z4-Y4*Z1);
00677   double S1 =  (X2-X4)*(Y1*Z3-Y3*Z1);
00678   double S2 = -(X3-X4)*(Y1*Z2-Y2*Z1);
00679 
00680   return (Q1+Q2+R1+R2+S1+S2)/6.0;
00681 }
00682 
00683 //=======================================================================
00684 //function : GetSize
00685 //purpose  : Return element volume
00686 //=======================================================================
00687 
00688 double SMDS_VolumeTool::GetSize() const
00689 {
00690   double V = 0.;
00691   if ( !myVolume )
00692     return 0.;
00693 
00694   if ( myVolume->IsPoly() )
00695   {
00696     if ( !myPolyedre )
00697       return 0.;
00698 
00699     // split a polyhedron into tetrahedrons
00700 
00701     int saveCurFace = myCurFace;
00702     SMDS_VolumeTool* me = const_cast< SMDS_VolumeTool* > ( this );
00703     for ( int f = 0; f < NbFaces(); ++f )
00704     {
00705       me->setFace( f );
00706       XYZ area (0,0,0), p1( myFaceNodes[0] );
00707       for ( int n = 0; n < myFaceNbNodes; ++n )
00708       {
00709         XYZ p2( myFaceNodes[ n+1 ]);
00710         area = area + p1.Crossed( p2 );
00711         p1 = p2;
00712       }
00713       V += p1.Dot( area );
00714     }
00715     V /= 6;
00716     if ( saveCurFace > -1 && saveCurFace != myCurFace )
00717       me->setFace( myCurFace );
00718   }
00719   else 
00720   {
00721     const static int ind[] = {
00722       0, 1, 3, 6, 11, 23, 31, 44, 58, 78 };
00723     const static int vtab[][4] = { // decomposition into tetra in the order of enum VolumeType
00724       // tetrahedron
00725       { 0, 1, 2, 3 },
00726       // pyramid
00727       { 0, 1, 3, 4 },
00728       { 1, 2, 3, 4 },
00729       // pentahedron
00730       { 0, 1, 2, 3 },
00731       { 1, 5, 3, 4 },
00732       { 1, 5, 2, 3 },
00733       // hexahedron
00734       { 1, 4, 3, 0 },
00735       { 4, 1, 6, 5 },
00736       { 1, 3, 6, 2 },
00737       { 4, 6, 3, 7 },
00738       { 1, 4, 6, 3 },
00739       // hexagonal prism
00740       { 0, 1, 2, 7 },
00741       { 0, 7, 8, 6 },
00742       { 2, 7, 8, 0 },
00743 
00744       { 0, 3, 4, 9 },
00745       { 0, 9, 10, 6 },
00746       { 4, 9, 10, 0 },
00747 
00748       { 0, 3, 4, 9 },
00749       { 0, 9, 10, 6 },
00750       { 4, 9, 10, 0 },
00751 
00752       { 0, 4, 5, 10 },
00753       { 0, 10, 11, 6 },
00754       { 5, 10, 11, 0 },
00755 
00756       // quadratic tetrahedron
00757       { 0, 4, 6, 7 },
00758       { 1, 5, 4, 8 },
00759       { 2, 6, 5, 9 },
00760       { 7, 8, 9, 3 },
00761       { 4, 6, 7, 9 },
00762       { 4, 5, 6, 9 },
00763       { 4, 7, 8, 9 },
00764       { 4, 5, 9, 8 },
00765 
00766       // quadratic pyramid
00767       { 0, 5, 8, 9 },
00768       { 1, 5,10, 6 },
00769       { 2, 6,11, 7 },
00770       { 3, 7,12, 8 },
00771       { 4, 9,11,10 },
00772       { 4, 9,12,11 },
00773       { 10, 5, 9, 8 },
00774       { 10, 8, 9,12 },
00775       { 10, 8,12, 7 },
00776       { 10, 7,12,11 },
00777       { 10, 7,11, 6 },
00778       { 10, 5, 8, 6 },
00779       { 10, 6, 8, 7 },
00780 
00781       // quadratic pentahedron
00782       { 12, 0, 8, 6 },
00783       { 12, 8, 7, 6 },
00784       { 12, 8, 2, 7 },
00785       { 12, 6, 7, 1 },
00786       { 12, 1, 7,13 },
00787       { 12, 7, 2,13 },
00788       { 12, 2,14,13 },
00789 
00790       { 12, 3, 9,11 },
00791       { 12,11, 9,10 },
00792       { 12,11,10, 5 },
00793       { 12, 9, 4,10 },
00794       { 12,14, 5,10 },
00795       { 12,14,10, 4 },
00796       { 12,14, 4,13 },
00797 
00798       // quadratic hexahedron
00799       { 16, 0,11, 8 },
00800       { 16,11, 9, 8 },
00801       { 16, 8, 9, 1 },
00802       { 16,11, 3,10 },
00803       { 16,11,10, 9 },
00804       { 16,10, 2, 9 },
00805       { 16, 3,19, 2 },
00806       { 16, 2,19,18 },
00807       { 16, 2,18,17 },
00808       { 16, 2,17, 1 },
00809 
00810       { 16, 4,12,15 },
00811       { 16,12, 5,13 },
00812       { 16,12,13,15 },
00813       { 16,13, 6,14 },
00814       { 16,13,14,15 },
00815       { 16,14, 7,15 },
00816       { 16, 6, 5,17 },
00817       { 16,18, 6,17 },
00818       { 16,18, 7, 6 },
00819       { 16,18,19, 7 },
00820 
00821     };
00822 
00823     int type = GetVolumeType();
00824     int n1 = ind[type];
00825     int n2 = ind[type+1];
00826 
00827     for (int i = n1; i <  n2; i++) {
00828       V -= getTetraVolume( myVolumeNodes[ vtab[i][0] ],
00829                            myVolumeNodes[ vtab[i][1] ],
00830                            myVolumeNodes[ vtab[i][2] ],
00831                            myVolumeNodes[ vtab[i][3] ]);
00832     }
00833   }
00834   return V;
00835 }
00836 
00837 //=======================================================================
00838 //function : GetBaryCenter
00839 //purpose  : 
00840 //=======================================================================
00841 
00842 bool SMDS_VolumeTool::GetBaryCenter(double & X, double & Y, double & Z) const
00843 {
00844   X = Y = Z = 0.;
00845   if ( !myVolume )
00846     return false;
00847 
00848   for ( int i = 0; i < myVolumeNbNodes; i++ ) {
00849     X += myVolumeNodes[ i ]->X();
00850     Y += myVolumeNodes[ i ]->Y();
00851     Z += myVolumeNodes[ i ]->Z();
00852   }
00853   X /= myVolumeNbNodes;
00854   Y /= myVolumeNbNodes;
00855   Z /= myVolumeNbNodes;
00856 
00857   return true;
00858 }
00859 
00860 //================================================================================
00865 //================================================================================
00866 
00867 bool SMDS_VolumeTool::IsOut(double X, double Y, double Z, double tol) const
00868 {
00869   // LIMITATION: for convex volumes only
00870   XYZ p( X,Y,Z );
00871   for ( int iF = 0; iF < myNbFaces; ++iF )
00872   {
00873     XYZ faceNormal;
00874     if ( !GetFaceNormal( iF, faceNormal.x, faceNormal.y, faceNormal.z ))
00875       continue;
00876     if ( !IsFaceExternal( iF ))
00877       faceNormal = XYZ() - faceNormal; // reverse
00878 
00879     XYZ face2p( p - XYZ( myFaceNodes[0] ));
00880     if ( face2p.Dot( faceNormal ) > tol )
00881       return true;
00882   }
00883   return false;
00884 }
00885 
00886 //=======================================================================
00887 //function : SetExternalNormal
00888 //purpose  : Node order will be so that faces normals are external
00889 //=======================================================================
00890 
00891 void SMDS_VolumeTool::SetExternalNormal ()
00892 {
00893   myExternalFaces = true;
00894   myCurFace = -1;
00895 }
00896 
00897 //=======================================================================
00898 //function : NbFaceNodes
00899 //purpose  : Return number of nodes in the array of face nodes
00900 //=======================================================================
00901 
00902 int SMDS_VolumeTool::NbFaceNodes( int faceIndex ) const
00903 {
00904     if ( !setFace( faceIndex ))
00905       return 0;
00906     return myFaceNbNodes;
00907 }
00908 
00909 //=======================================================================
00910 //function : GetFaceNodes
00911 //purpose  : Return pointer to the array of face nodes.
00912 //           To comfort link iteration, the array
00913 //           length == NbFaceNodes( faceIndex ) + 1 and
00914 //           the last node == the first one.
00915 //=======================================================================
00916 
00917 const SMDS_MeshNode** SMDS_VolumeTool::GetFaceNodes( int faceIndex ) const
00918 {
00919   if ( !setFace( faceIndex ))
00920     return 0;
00921   return myFaceNodes;
00922 }
00923 
00924 //=======================================================================
00925 //function : GetFaceNodesIndices
00926 //purpose  : Return pointer to the array of face nodes indices
00927 //           To comfort link iteration, the array
00928 //           length == NbFaceNodes( faceIndex ) + 1 and
00929 //           the last node index == the first one.
00930 //=======================================================================
00931 
00932 const int* SMDS_VolumeTool::GetFaceNodesIndices( int faceIndex ) const
00933 {
00934   if ( !setFace( faceIndex ))
00935     return 0;
00936 
00937   if (myPolyedre)
00938   {
00939     SMDS_VolumeTool* me = const_cast< SMDS_VolumeTool* > ( this );
00940     me->myPolyIndices.resize( myFaceNbNodes + 1 );
00941     me->myFaceNodeIndices = & me->myPolyIndices[0];
00942     for ( int i = 0; i <= myFaceNbNodes; ++i )
00943       me->myFaceNodeIndices[i] = myVolume->GetNodeIndex( myFaceNodes[i] );
00944   }
00945   return myFaceNodeIndices;
00946 }
00947 
00948 //=======================================================================
00949 //function : GetFaceNodes
00950 //purpose  : Return a set of face nodes.
00951 //=======================================================================
00952 
00953 bool SMDS_VolumeTool::GetFaceNodes (int                        faceIndex,
00954                                     set<const SMDS_MeshNode*>& theFaceNodes ) const
00955 {
00956   if ( !setFace( faceIndex ))
00957     return false;
00958 
00959   theFaceNodes.clear();
00960   theFaceNodes.insert( myFaceNodes, myFaceNodes + myFaceNbNodes );
00961 
00962   return true;
00963 }
00964 
00965 //=======================================================================
00966 //function : IsFaceExternal
00967 //purpose  : Check normal orientation of a given face
00968 //=======================================================================
00969 
00970 bool SMDS_VolumeTool::IsFaceExternal( int faceIndex ) const
00971 {
00972   if ( myExternalFaces || !myVolume )
00973     return true;
00974 
00975   if (myVolume->IsPoly()) {
00976     XYZ aNormal, baryCenter, p0 (myPolyedre->GetFaceNode(faceIndex + 1, 1));
00977     GetFaceNormal(faceIndex, aNormal.x, aNormal.y, aNormal.z);
00978     GetBaryCenter(baryCenter.x, baryCenter.y, baryCenter.z);
00979     XYZ insideVec (baryCenter - p0);
00980     if (insideVec.Dot(aNormal) > 0)
00981       return false;
00982     return true;
00983   }
00984 
00985   // switch ( myVolumeNbNodes ) {
00986   // case 4:
00987   // case 5:
00988   // case 10:
00989   // case 13:
00990   //   // only the bottom of a reversed tetrahedron can be internal
00991   //   return ( myVolForward || faceIndex != 0 );
00992   // case 6:
00993   // case 15:
00994   // case 12:
00995   //   // in a forward prism, the top is internal, in a reversed one - bottom
00996   //   return ( myVolForward ? faceIndex != 1 : faceIndex != 0 );
00997   // case 8:
00998   // case 20:
00999   // case 27: {
01000   //   // in a forward hexahedron, even face normal is external, odd - internal
01001   //   bool odd = faceIndex % 2;
01002   //   return ( myVolForward ? !odd : odd );
01003   // }
01004   // default:;
01005   // }
01006   // return false;
01007   return true;
01008 }
01009 
01010 //=======================================================================
01011 //function : GetFaceNormal
01012 //purpose  : Return a normal to a face
01013 //=======================================================================
01014 
01015 bool SMDS_VolumeTool::GetFaceNormal (int faceIndex, double & X, double & Y, double & Z) const
01016 {
01017   if ( !setFace( faceIndex ))
01018     return false;
01019 
01020   const int iQuad = ( myFaceNbNodes > 6 && !myPolyedre ) ? 2 : 1;
01021   XYZ p1 ( myFaceNodes[0*iQuad] );
01022   XYZ p2 ( myFaceNodes[1*iQuad] );
01023   XYZ p3 ( myFaceNodes[2*iQuad] );
01024   XYZ aVec12( p2 - p1 );
01025   XYZ aVec13( p3 - p1 );
01026   XYZ cross = aVec12.Crossed( aVec13 );
01027 
01028   if ( myFaceNbNodes >3*iQuad ) {
01029     XYZ p4 ( myFaceNodes[3*iQuad] );
01030     XYZ aVec14( p4 - p1 );
01031     XYZ cross2 = aVec13.Crossed( aVec14 );
01032     cross = cross + cross2;
01033   }
01034 
01035   double size = cross.Magnitude();
01036   if ( size <= numeric_limits<double>::min() )
01037     return false;
01038 
01039   X = cross.x / size;
01040   Y = cross.y / size;
01041   Z = cross.z / size;
01042 
01043   return true;
01044 }
01045 
01046 //================================================================================
01050 //================================================================================
01051 
01052 bool SMDS_VolumeTool::GetFaceBaryCenter (int faceIndex, double & X, double & Y, double & Z) const
01053 {
01054   if ( !setFace( faceIndex ))
01055     return false;
01056 
01057   X = Y = Z = 0.0;
01058   for ( int i = 0; i < myFaceNbNodes; ++i )
01059   {
01060     X += myFaceNodes[i]->X() / myFaceNbNodes;
01061     Y += myFaceNodes[i]->Y() / myFaceNbNodes;
01062     Z += myFaceNodes[i]->Z() / myFaceNbNodes;
01063   }
01064   return true;
01065 }
01066 
01067 //=======================================================================
01068 //function : GetFaceArea
01069 //purpose  : Return face area
01070 //=======================================================================
01071 
01072 double SMDS_VolumeTool::GetFaceArea( int faceIndex ) const
01073 {
01074   if (myVolume->IsPoly()) {
01075     MESSAGE("Warning: attempt to obtain area of a face of polyhedral volume");
01076     return 0;
01077   }
01078 
01079   if ( !setFace( faceIndex ))
01080     return 0;
01081 
01082   XYZ p1 ( myFaceNodes[0] );
01083   XYZ p2 ( myFaceNodes[1] );
01084   XYZ p3 ( myFaceNodes[2] );
01085   XYZ aVec12( p2 - p1 );
01086   XYZ aVec13( p3 - p1 );
01087   double area = aVec12.Crossed( aVec13 ).Magnitude() * 0.5;
01088 
01089   if ( myFaceNbNodes == 4 ) {
01090     XYZ p4 ( myFaceNodes[3] );
01091     XYZ aVec14( p4 - p1 );
01092     area += aVec14.Crossed( aVec13 ).Magnitude() * 0.5;
01093   }
01094   return area;
01095 }
01096 
01097 //================================================================================
01101 //================================================================================
01102 
01103 int SMDS_VolumeTool::GetCenterNodeIndex( int faceIndex ) const
01104 {
01105   if ( myAllFacesNbNodes && myVolumeNbNodes == 27 ) // classic element with 27 nodes
01106   {
01107     switch ( faceIndex ) {
01108     case 0: return 20;
01109     case 1: return 25;
01110     default:
01111       return faceIndex + 19;
01112     }
01113   }
01114   return -1;
01115 }
01116 
01117 //=======================================================================
01118 //function : GetOppFaceIndex
01119 //purpose  : Return index of the opposite face if it exists, else -1.
01120 //=======================================================================
01121 
01122 int SMDS_VolumeTool::GetOppFaceIndex( int faceIndex ) const
01123 {
01124   int ind = -1;
01125   if (myPolyedre) {
01126     MESSAGE("Warning: attempt to obtain opposite face on polyhedral volume");
01127     return ind;
01128   }
01129 
01130   const int nbHoriFaces = 2;
01131 
01132   if ( faceIndex >= 0 && faceIndex < NbFaces() ) {
01133     switch ( myVolumeNbNodes ) {
01134     case 6:
01135     case 15:
01136       if ( faceIndex == 0 || faceIndex == 1 )
01137         ind = 1 - faceIndex;
01138         break;
01139     case 8:
01140     case 12:
01141       if ( faceIndex <= 1 ) // top or bottom
01142         ind = 1 - faceIndex;
01143       else {
01144         const int nbSideFaces = myAllFacesNbNodes[0];
01145         ind = ( faceIndex - nbHoriFaces + nbSideFaces/2 ) % nbSideFaces + nbHoriFaces;
01146       }
01147       break;
01148     case 20:
01149     case 27:
01150       if ( faceIndex <= 1 ) // top or bottom
01151         ind = 1 - faceIndex;
01152       else {
01153         const int nbSideFaces = myAllFacesNbNodes[0] / 2;
01154         ind = ( faceIndex - nbHoriFaces + nbSideFaces/2 ) % nbSideFaces + nbHoriFaces;
01155       }
01156       break;
01157     default:;
01158     }
01159   }
01160   return ind;
01161 }
01162 
01163 //=======================================================================
01164 //function : IsLinked
01165 //purpose  : return true if theNode1 is linked with theNode2
01166 // If theIgnoreMediumNodes then corner nodes of quadratic cell are considered linked as well
01167 //=======================================================================
01168 
01169 bool SMDS_VolumeTool::IsLinked (const SMDS_MeshNode* theNode1,
01170                                 const SMDS_MeshNode* theNode2,
01171                                 const bool           theIgnoreMediumNodes) const
01172 {
01173   if ( !myVolume )
01174     return false;
01175 
01176   if (myVolume->IsPoly()) {
01177     if (!myPolyedre) {
01178       MESSAGE("Warning: bad volumic element");
01179       return false;
01180     }
01181     bool isLinked = false;
01182     int iface;
01183     for (iface = 1; iface <= myNbFaces && !isLinked; iface++) {
01184       int inode, nbFaceNodes = myPolyedre->NbFaceNodes(iface);
01185 
01186       for (inode = 1; inode <= nbFaceNodes && !isLinked; inode++) {
01187         const SMDS_MeshNode* curNode = myPolyedre->GetFaceNode(iface, inode);
01188 
01189         if (curNode == theNode1 || curNode == theNode2) {
01190           int inextnode = (inode == nbFaceNodes) ? 1 : inode + 1;
01191           const SMDS_MeshNode* nextNode = myPolyedre->GetFaceNode(iface, inextnode);
01192 
01193           if ((curNode == theNode1 && nextNode == theNode2) ||
01194               (curNode == theNode2 && nextNode == theNode1)) {
01195             isLinked = true;
01196           }
01197         }
01198       }
01199     }
01200     return isLinked;
01201   }
01202 
01203   // find nodes indices
01204   int i1 = -1, i2 = -1, nbFound = 0;
01205   for ( int i = 0; i < myVolumeNbNodes && nbFound < 2; i++ )
01206   {
01207     if ( myVolumeNodes[ i ] == theNode1 )
01208       i1 = i, ++nbFound;
01209     else if ( myVolumeNodes[ i ] == theNode2 )
01210       i2 = i, ++nbFound;
01211   }
01212   return IsLinked( i1, i2 );
01213 }
01214 
01215 //=======================================================================
01216 //function : IsLinked
01217 //purpose  : return true if the node with theNode1Index is linked
01218 //           with the node with theNode2Index
01219 // If theIgnoreMediumNodes then corner nodes of quadratic cell are considered linked as well
01220 //=======================================================================
01221 
01222 bool SMDS_VolumeTool::IsLinked (const int theNode1Index,
01223                                 const int theNode2Index,
01224                                 bool      theIgnoreMediumNodes) const
01225 {
01226   if ( myVolume->IsPoly() ) {
01227     return IsLinked(myVolumeNodes[theNode1Index], myVolumeNodes[theNode2Index]);
01228   }
01229 
01230   int minInd = min( theNode1Index, theNode2Index );
01231   int maxInd = max( theNode1Index, theNode2Index );
01232 
01233   if ( minInd < 0 || maxInd > myVolumeNbNodes - 1 || maxInd == minInd )
01234     return false;
01235 
01236   VolumeType type = GetVolumeType();
01237   if ( myVolume->IsQuadratic() )
01238   {
01239     int firstMediumInd = myVolume->NbCornerNodes();
01240     if ( minInd >= firstMediumInd )
01241       return false; // both nodes are medium - not linked
01242     if ( maxInd < firstMediumInd ) // both nodes are corners
01243     {
01244       if ( theIgnoreMediumNodes )
01245         type = quadToLinear(type); // to check linkage of corner nodes only
01246       else
01247         return false; // corner nodes are not linked directly in a quadratic cell
01248     }
01249   }
01250 
01251   switch ( type ) {
01252   case TETRA:
01253     return true;
01254   case HEXA:
01255     switch ( maxInd - minInd ) {
01256     case 1: return minInd != 3;
01257     case 3: return minInd == 0 || minInd == 4;
01258     case 4: return true;
01259     default:;
01260     }
01261     break;
01262   case PYRAM:
01263     if ( maxInd == 4 )
01264       return true;
01265     switch ( maxInd - minInd ) {
01266     case 1:
01267     case 3: return true;
01268     default:;
01269     }
01270     break;
01271   case PENTA:
01272     switch ( maxInd - minInd ) {
01273     case 1: return minInd != 2;
01274     case 2: return minInd == 0 || minInd == 3;
01275     case 3: return true;
01276     default:;
01277     }
01278     break;
01279   case QUAD_TETRA:
01280     {
01281       switch ( minInd ) {
01282       case 0: if( maxInd==4 ||  maxInd==6 ||  maxInd==7 ) return true;
01283       case 1: if( maxInd==4 ||  maxInd==5 ||  maxInd==8 ) return true;
01284       case 2: if( maxInd==5 ||  maxInd==6 ||  maxInd==9 ) return true;
01285       case 3: if( maxInd==7 ||  maxInd==8 ||  maxInd==9 ) return true;
01286       default:;
01287       }
01288       break;
01289     }
01290   case QUAD_HEXA:
01291     {
01292       switch ( minInd ) {
01293       case 0: if( maxInd==8 ||  maxInd==11 ||  maxInd==16 ) return true;
01294       case 1: if( maxInd==8 ||  maxInd==9 ||  maxInd==17 ) return true;
01295       case 2: if( maxInd==9 ||  maxInd==10 ||  maxInd==18 ) return true;
01296       case 3: if( maxInd==10 ||  maxInd==11 ||  maxInd==19 ) return true;
01297       case 4: if( maxInd==12 ||  maxInd==15 ||  maxInd==16 ) return true;
01298       case 5: if( maxInd==12 ||  maxInd==13 ||  maxInd==17 ) return true;
01299       case 6: if( maxInd==13 ||  maxInd==14 ||  maxInd==18 ) return true;
01300       case 7: if( maxInd==14 ||  maxInd==15 ||  maxInd==19 ) return true;
01301       default:;
01302       }
01303       break;
01304     }
01305   case QUAD_PYRAM:
01306     {
01307       switch ( minInd ) {
01308       case 0: if( maxInd==5 ||  maxInd==8 ||  maxInd==9 ) return true;
01309       case 1: if( maxInd==5 ||  maxInd==6 ||  maxInd==10 ) return true;
01310       case 2: if( maxInd==6 ||  maxInd==7 ||  maxInd==11 ) return true;
01311       case 3: if( maxInd==7 ||  maxInd==8 ||  maxInd==12 ) return true;
01312       case 4: if( maxInd==9 ||  maxInd==10 ||  maxInd==11 ||  maxInd==12 ) return true;
01313       default:;
01314       }
01315       break;
01316     }
01317   case QUAD_PENTA:
01318     {
01319       switch ( minInd ) {
01320       case 0: if( maxInd==6 ||  maxInd==8 ||  maxInd==12 ) return true;
01321       case 1: if( maxInd==6 ||  maxInd==7 ||  maxInd==13 ) return true;
01322       case 2: if( maxInd==7 ||  maxInd==8 ||  maxInd==14 ) return true;
01323       case 3: if( maxInd==9 ||  maxInd==11 ||  maxInd==12 ) return true;
01324       case 4: if( maxInd==9 ||  maxInd==10 ||  maxInd==13 ) return true;
01325       case 5: if( maxInd==10 ||  maxInd==11 ||  maxInd==14 ) return true;
01326       default:;
01327       }
01328       break;
01329     }
01330   case HEX_PRISM:
01331     {
01332       const int diff = maxInd-minInd;
01333       if ( diff > 6  ) return false;// not linked top and bottom
01334       if ( diff == 6 ) return true; // linked top and bottom
01335       return diff == 1 || diff == 7;
01336     }
01337   default:;
01338   }
01339   return false;
01340 }
01341 
01342 //=======================================================================
01343 //function : GetNodeIndex
01344 //purpose  : Return an index of theNode
01345 //=======================================================================
01346 
01347 int SMDS_VolumeTool::GetNodeIndex(const SMDS_MeshNode* theNode) const
01348 {
01349   if ( myVolume ) {
01350     for ( int i = 0; i < myVolumeNbNodes; i++ ) {
01351       if ( myVolumeNodes[ i ] == theNode )
01352         return i;
01353     }
01354   }
01355   return -1;
01356 }
01357 
01358 //================================================================================
01364 //================================================================================
01365 
01366 int SMDS_VolumeTool::GetAllExistingFaces(vector<const SMDS_MeshElement*> & faces) const
01367 {
01368   faces.clear();
01369   for ( int iF = 0; iF < NbFaces(); ++iF ) {
01370     const SMDS_MeshFace* face = 0;
01371     const SMDS_MeshNode** nodes = GetFaceNodes( iF );
01372     switch ( NbFaceNodes( iF )) {
01373     case 3:
01374       face = SMDS_Mesh::FindFace( nodes[0], nodes[1], nodes[2] ); break;
01375     case 4:
01376       face = SMDS_Mesh::FindFace( nodes[0], nodes[1], nodes[2], nodes[3] ); break;
01377     case 6:
01378       face = SMDS_Mesh::FindFace( nodes[0], nodes[1], nodes[2],
01379                                   nodes[3], nodes[4], nodes[5]); break;
01380     case 8:
01381       face = SMDS_Mesh::FindFace( nodes[0], nodes[1], nodes[2], nodes[3],
01382                                   nodes[4], nodes[5], nodes[6], nodes[7]); break;
01383     }
01384     if ( face )
01385       faces.push_back( face );
01386   }
01387   return faces.size();
01388 }
01389 
01390 
01391 //================================================================================
01397 //================================================================================
01398 
01399 int SMDS_VolumeTool::GetAllExistingEdges(vector<const SMDS_MeshElement*> & edges) const
01400 {
01401   edges.clear();
01402   edges.reserve( myVolumeNbNodes * 2 );
01403   for ( int i = 0; i < myVolumeNbNodes-1; ++i ) {
01404     for ( int j = i + 1; j < myVolumeNbNodes; ++j ) {
01405       if ( IsLinked( i, j )) {
01406         const SMDS_MeshElement* edge =
01407           SMDS_Mesh::FindEdge( myVolumeNodes[i], myVolumeNodes[j] );
01408         if ( edge )
01409           edges.push_back( edge );
01410       }
01411     }
01412   }
01413   return edges.size();
01414 }
01415 
01416 //================================================================================
01420 //================================================================================
01421 
01422 double SMDS_VolumeTool::MinLinearSize2() const
01423 {
01424   double minSize = 1e+100;
01425   int iQ = myVolume->IsQuadratic() ? 2 : 1;
01426 
01427   // store current face data
01428   int curFace = myCurFace, nbN = myFaceNbNodes;
01429   int* ind = myFaceNodeIndices;
01430   myFaceNodeIndices = NULL;
01431   const SMDS_MeshNode** nodes = myFaceNodes;
01432   myFaceNodes = NULL;
01433   
01434   // it seems that compute distance twice is faster than organization of a sole computing
01435   myCurFace = -1;
01436   for ( int iF = 0; iF < myNbFaces; ++iF )
01437   {
01438     setFace( iF );
01439     for ( int iN = 0; iN < myFaceNbNodes; iN += iQ )
01440     {
01441       XYZ n1( myFaceNodes[ iN ]);
01442       XYZ n2( myFaceNodes[(iN + iQ) % myFaceNbNodes]);
01443       minSize = std::min( minSize, (n1 - n2).SquareMagnitude());
01444     }
01445   }
01446   // restore current face data
01447   myCurFace = curFace;
01448   myFaceNbNodes = nbN;
01449   myFaceNodeIndices = ind;
01450   delete [] myFaceNodes; myFaceNodes = nodes;
01451 
01452   return minSize;
01453 }
01454 
01455 //================================================================================
01461 //================================================================================
01462 
01463 bool SMDS_VolumeTool::IsFreeFace( int faceIndex, const SMDS_MeshElement** otherVol/*=0*/ ) const
01464 {
01465   const bool isFree = true;
01466 
01467   if (!setFace( faceIndex ))
01468     return !isFree;
01469 
01470   const SMDS_MeshNode** nodes = GetFaceNodes( faceIndex );
01471   const int nbFaceNodes = myFaceNbNodes;
01472 
01473   // evaluate nb of face nodes shared by other volumes
01474   int maxNbShared = -1;
01475   typedef map< const SMDS_MeshElement*, int > TElemIntMap;
01476   TElemIntMap volNbShared;
01477   TElemIntMap::iterator vNbIt;
01478   for ( int iNode = 0; iNode < nbFaceNodes; iNode++ ) {
01479     const SMDS_MeshNode* n = nodes[ iNode ];
01480     SMDS_ElemIteratorPtr eIt = n->GetInverseElementIterator( SMDSAbs_Volume );
01481     while ( eIt->more() ) {
01482       const SMDS_MeshElement* elem = eIt->next();
01483       if ( elem != myVolume ) {
01484         vNbIt = volNbShared.insert( make_pair( elem, 0 )).first;
01485         (*vNbIt).second++;
01486         if ( vNbIt->second > maxNbShared )
01487           maxNbShared = vNbIt->second;
01488       }
01489     }
01490   }
01491   if ( maxNbShared < 3 )
01492     return isFree; // is free
01493 
01494   // find volumes laying on the opposite side of the face
01495   // and sharing all nodes
01496   XYZ intNormal; // internal normal
01497   GetFaceNormal( faceIndex, intNormal.x, intNormal.y, intNormal.z );
01498   if ( IsFaceExternal( faceIndex ))
01499     intNormal = XYZ( -intNormal.x, -intNormal.y, -intNormal.z );
01500   XYZ p0 ( nodes[0] ), baryCenter;
01501   for ( vNbIt = volNbShared.begin(); vNbIt != volNbShared.end();  ) {
01502     const int& nbShared = (*vNbIt).second;
01503     if ( nbShared >= 3 ) {
01504       SMDS_VolumeTool volume( (*vNbIt).first );
01505       volume.GetBaryCenter( baryCenter.x, baryCenter.y, baryCenter.z );
01506       XYZ intNormal2( baryCenter - p0 );
01507       if ( intNormal.Dot( intNormal2 ) < 0 ) {
01508         // opposite side
01509         if ( nbShared >= nbFaceNodes )
01510         {
01511           // a volume shares the whole facet
01512           if ( otherVol ) *otherVol = vNbIt->first;
01513           return !isFree; 
01514         }
01515         ++vNbIt;
01516         continue;
01517       }
01518     }
01519     // remove a volume from volNbShared map
01520     volNbShared.erase( vNbIt++ );
01521   }
01522 
01523   // here volNbShared contains only volumes laying on the opposite side of
01524   // the face and sharing 3 or more but not all face nodes with myVolume
01525   if ( volNbShared.size() < 2 ) {
01526     return isFree; // is free
01527   }
01528 
01529   // check if the whole area of a face is shared
01530   for ( int iNode = 0; iNode < nbFaceNodes; iNode++ )
01531   {
01532     const SMDS_MeshNode* n = nodes[ iNode ];
01533     // check if n is shared by one of volumes of volNbShared
01534     bool isShared = false;
01535     SMDS_ElemIteratorPtr eIt = n->GetInverseElementIterator( SMDSAbs_Volume );
01536     while ( eIt->more() && !isShared )
01537       isShared = volNbShared.count( eIt->next() );
01538     if ( !isShared )
01539       return isFree;
01540   }
01541   if ( otherVol ) *otherVol = volNbShared.begin()->first;
01542   return !isFree;
01543 
01544 //   if ( !myVolume->IsPoly() )
01545 //   {
01546 //     bool isShared[] = { false, false, false, false }; // 4 triangle parts of a quadrangle
01547 //     for ( vNbIt = volNbShared.begin(); vNbIt != volNbShared.end(); vNbIt++ ) {
01548 //       SMDS_VolumeTool volume( (*vNbIt).first );
01549 //       bool prevLinkShared = false;
01550 //       int nbSharedLinks = 0;
01551 //       for ( int iNode = 0; iNode < nbFaceNodes; iNode++ ) {
01552 //         bool linkShared = volume.IsLinked( nodes[ iNode ], nodes[ iNode + 1] );
01553 //         if ( linkShared )
01554 //           nbSharedLinks++;
01555 //         if ( linkShared && prevLinkShared &&
01556 //              volume.IsLinked( nodes[ iNode - 1 ], nodes[ iNode + 1] ))
01557 //           isShared[ iNode ] = true;
01558 //         prevLinkShared = linkShared;
01559 //       }
01560 //       if ( nbSharedLinks == nbFaceNodes )
01561 //         return !free; // is not free
01562 //       if ( nbFaceNodes == 4 ) {
01563 //         // check traingle parts 1 & 3
01564 //         if ( isShared[1] && isShared[3] )
01565 //           return !free; // is not free
01566 //         // check triangle parts 0 & 2;
01567 //         // 0 part could not be checked in the loop; check it here
01568 //         if ( isShared[2] && prevLinkShared &&
01569 //              volume.IsLinked( nodes[ 0 ], nodes[ 1 ] ) &&
01570 //              volume.IsLinked( nodes[ 1 ], nodes[ 3 ] ) )
01571 //           return !free; // is not free
01572 //       }
01573 //     }
01574 //   }
01575 //  return free;
01576 }
01577 
01578 //=======================================================================
01579 //function : GetFaceIndex
01580 //purpose  : Return index of a face formed by theFaceNodes
01581 //=======================================================================
01582 
01583 int SMDS_VolumeTool::GetFaceIndex( const set<const SMDS_MeshNode*>& theFaceNodes ) const
01584 {
01585   for ( int iFace = 0; iFace < myNbFaces; iFace++ ) {
01586     const SMDS_MeshNode** nodes = GetFaceNodes( iFace );
01587     int nbFaceNodes = NbFaceNodes( iFace );
01588     set<const SMDS_MeshNode*> nodeSet;
01589     for ( int iNode = 0; iNode < nbFaceNodes; iNode++ )
01590       nodeSet.insert( nodes[ iNode ] );
01591     if ( theFaceNodes == nodeSet )
01592       return iFace;
01593   }
01594   return -1;
01595 }
01596 
01597 //=======================================================================
01598 //function : GetFaceIndex
01599 //purpose  : Return index of a face formed by theFaceNodes
01600 //=======================================================================
01601 
01602 /*int SMDS_VolumeTool::GetFaceIndex( const set<int>& theFaceNodesIndices )
01603 {
01604   for ( int iFace = 0; iFace < myNbFaces; iFace++ ) {
01605     const int* nodes = GetFaceNodesIndices( iFace );
01606     int nbFaceNodes = NbFaceNodes( iFace );
01607     set<int> nodeSet;
01608     for ( int iNode = 0; iNode < nbFaceNodes; iNode++ )
01609       nodeSet.insert( nodes[ iNode ] );
01610     if ( theFaceNodesIndices == nodeSet )
01611       return iFace;
01612   }
01613   return -1;
01614 }*/
01615 
01616 //=======================================================================
01617 //function : setFace
01618 //purpose  : 
01619 //=======================================================================
01620 
01621 bool SMDS_VolumeTool::setFace( int faceIndex ) const
01622 {
01623   if ( !myVolume )
01624     return false;
01625 
01626   if ( myCurFace == faceIndex )
01627     return true;
01628 
01629   myCurFace = -1;
01630 
01631   if ( faceIndex < 0 || faceIndex >= NbFaces() )
01632     return false;
01633 
01634   if (myFaceNodes != NULL) {
01635     delete [] myFaceNodes;
01636     myFaceNodes = NULL;
01637   }
01638 
01639   if (myVolume->IsPoly())
01640   {
01641     if (!myPolyedre) {
01642       MESSAGE("Warning: bad volumic element");
01643       return false;
01644     }
01645 
01646     // set face nodes
01647     int iNode;
01648     myFaceNbNodes = myPolyedre->NbFaceNodes(faceIndex + 1);
01649     myFaceNodes = new const SMDS_MeshNode* [myFaceNbNodes + 1];
01650     for ( iNode = 0; iNode < myFaceNbNodes; iNode++ )
01651       myFaceNodes[ iNode ] = myPolyedre->GetFaceNode(faceIndex + 1, iNode + 1);
01652     myFaceNodes[ myFaceNbNodes ] = myFaceNodes[ 0 ]; // last = first
01653 
01654     // check orientation
01655     if (myExternalFaces)
01656     {
01657       myCurFace = faceIndex; // avoid infinite recursion in IsFaceExternal()
01658       myExternalFaces = false; // force normal computation by IsFaceExternal()
01659       if ( !IsFaceExternal( faceIndex ))
01660         for ( int i = 0, j = myFaceNbNodes; i < j; ++i, --j )
01661           std::swap( myFaceNodes[i], myFaceNodes[j] );
01662       myExternalFaces = true;
01663     }
01664   }
01665   else
01666   {
01667     if ( !myAllFacesNodeIndices_F )
01668     {
01669       // choose data for an element type
01670       switch ( myVolumeNbNodes ) {
01671       case 4:
01672         myAllFacesNodeIndices_F  = &Tetra_F [0][0];
01673         //myAllFacesNodeIndices_FE = &Tetra_F [0][0];
01674         myAllFacesNodeIndices_RE = &Tetra_RE[0][0];
01675         myAllFacesNbNodes        = Tetra_nbN;
01676         myMaxFaceNbNodes         = sizeof(Tetra_F[0])/sizeof(Tetra_F[0][0]);
01677         break;
01678       case 5:
01679         myAllFacesNodeIndices_F  = &Pyramid_F [0][0];
01680         //myAllFacesNodeIndices_FE = &Pyramid_F [0][0];
01681         myAllFacesNodeIndices_RE = &Pyramid_RE[0][0];
01682         myAllFacesNbNodes        = Pyramid_nbN;
01683         myMaxFaceNbNodes         = sizeof(Pyramid_F[0])/sizeof(Pyramid_F[0][0]);
01684         break;
01685       case 6:
01686         myAllFacesNodeIndices_F  = &Penta_F [0][0];
01687         //myAllFacesNodeIndices_FE = &Penta_FE[0][0];
01688         myAllFacesNodeIndices_RE = &Penta_RE[0][0];
01689         myAllFacesNbNodes        = Penta_nbN;
01690         myMaxFaceNbNodes         = sizeof(Penta_F[0])/sizeof(Penta_F[0][0]);
01691         break;
01692       case 8:
01693         myAllFacesNodeIndices_F  = &Hexa_F [0][0];
01695         myAllFacesNodeIndices_RE = &Hexa_RE[0][0];
01696         myAllFacesNbNodes        = Hexa_nbN;
01697         myMaxFaceNbNodes         = sizeof(Hexa_F[0])/sizeof(Hexa_F[0][0]);
01698         break;
01699       case 10:
01700         myAllFacesNodeIndices_F  = &QuadTetra_F [0][0];
01701         //myAllFacesNodeIndices_FE = &QuadTetra_F [0][0];
01702         myAllFacesNodeIndices_RE = &QuadTetra_RE[0][0];
01703         myAllFacesNbNodes        = QuadTetra_nbN;
01704         myMaxFaceNbNodes         = sizeof(QuadTetra_F[0])/sizeof(QuadTetra_F[0][0]);
01705         break;
01706       case 13:
01707         myAllFacesNodeIndices_F  = &QuadPyram_F [0][0];
01708         //myAllFacesNodeIndices_FE = &QuadPyram_F [0][0];
01709         myAllFacesNodeIndices_RE = &QuadPyram_RE[0][0];
01710         myAllFacesNbNodes        = QuadPyram_nbN;
01711         myMaxFaceNbNodes         = sizeof(QuadPyram_F[0])/sizeof(QuadPyram_F[0][0]);
01712         break;
01713       case 15:
01714         myAllFacesNodeIndices_F  = &QuadPenta_F [0][0];
01715         //myAllFacesNodeIndices_FE = &QuadPenta_FE[0][0];
01716         myAllFacesNodeIndices_RE = &QuadPenta_RE[0][0];
01717         myAllFacesNbNodes        = QuadPenta_nbN;
01718         myMaxFaceNbNodes         = sizeof(QuadPenta_F[0])/sizeof(QuadPenta_F[0][0]);
01719         break;
01720       case 20:
01721       case 27:
01722         myAllFacesNodeIndices_F  = &QuadHexa_F [0][0];
01723         //myAllFacesNodeIndices_FE = &QuadHexa_FE[0][0];
01724         myAllFacesNodeIndices_RE = &QuadHexa_RE[0][0];
01725         myAllFacesNbNodes        = QuadHexa_nbN;
01726         myMaxFaceNbNodes         = sizeof(QuadHexa_F[0])/sizeof(QuadHexa_F[0][0]);
01727         if ( !myIgnoreCentralNodes && myVolumeNbNodes == 27 )
01728         {
01729           myAllFacesNodeIndices_F  = &TriQuadHexa_F [0][0];
01730           //myAllFacesNodeIndices_FE = &TriQuadHexa_FE[0][0];
01731           myAllFacesNodeIndices_RE = &TriQuadHexa_RE[0][0];
01732           myAllFacesNbNodes        = TriQuadHexa_nbN;
01733           myMaxFaceNbNodes         = sizeof(TriQuadHexa_F[0])/sizeof(TriQuadHexa_F[0][0]);
01734         }
01735         break;
01736       case 12:
01737         myAllFacesNodeIndices_F  = &HexPrism_F [0][0];
01738         //myAllFacesNodeIndices_FE = &HexPrism_FE[0][0];
01739         myAllFacesNodeIndices_RE = &HexPrism_RE[0][0];
01740         myAllFacesNbNodes        = HexPrism_nbN;
01741         myMaxFaceNbNodes         = sizeof(HexPrism_F[0])/sizeof(HexPrism_F[0][0]);
01742         break;
01743       default:
01744         return false;
01745       }
01746     }
01747     myFaceNbNodes = myAllFacesNbNodes[ faceIndex ];
01748     // if ( myExternalFaces )
01749     //   myFaceNodeIndices = (int*)( myVolForward ? myAllFacesNodeIndices_FE + faceIndex*myMaxFaceNbNodes : myAllFacesNodeIndices_RE + faceIndex*myMaxFaceNbNodes );
01750     // else
01751     //   myFaceNodeIndices = (int*)( myAllFacesNodeIndices_F + faceIndex*myMaxFaceNbNodes );
01752     myFaceNodeIndices = (int*)( myVolForward ? myAllFacesNodeIndices_F + faceIndex*myMaxFaceNbNodes : myAllFacesNodeIndices_RE + faceIndex*myMaxFaceNbNodes );
01753 
01754     // set face nodes
01755     myFaceNodes = new const SMDS_MeshNode* [myFaceNbNodes + 1];
01756     for ( int iNode = 0; iNode < myFaceNbNodes; iNode++ )
01757       myFaceNodes[ iNode ] = myVolumeNodes[ myFaceNodeIndices[ iNode ]];
01758     myFaceNodes[ myFaceNbNodes ] = myFaceNodes[ 0 ];
01759   }
01760 
01761   myCurFace = faceIndex;
01762 
01763   return true;
01764 }
01765 
01766 //=======================================================================
01767 //function : GetType
01768 //purpose  : return VolumeType by nb of nodes in a volume
01769 //=======================================================================
01770 
01771 SMDS_VolumeTool::VolumeType SMDS_VolumeTool::GetType(int nbNodes)
01772 {
01773   switch ( nbNodes ) {
01774   case 4: return TETRA;
01775   case 5: return PYRAM;
01776   case 6: return PENTA;
01777   case 8: return HEXA;
01778   case 10: return QUAD_TETRA;
01779   case 13: return QUAD_PYRAM;
01780   case 15: return QUAD_PENTA;
01781   case 20:
01782   case 27: return QUAD_HEXA;
01783   case 12: return HEX_PRISM;
01784   default:return UNKNOWN;
01785   }
01786 }
01787 
01788 //=======================================================================
01789 //function : NbFaces
01790 //purpose  : return nb of faces by volume type
01791 //=======================================================================
01792 
01793 int SMDS_VolumeTool::NbFaces( VolumeType type )
01794 {
01795   switch ( type ) {
01796   case TETRA     :
01797   case QUAD_TETRA: return 4;
01798   case PYRAM     :
01799   case QUAD_PYRAM: return 5;
01800   case PENTA     :
01801   case QUAD_PENTA: return 5;
01802   case HEXA      :
01803   case QUAD_HEXA : return 6;
01804   case HEX_PRISM : return 8;
01805   default:         return 0;
01806   }
01807 }
01808 
01809 //================================================================================
01815 //================================================================================
01816 
01817 int SMDS_VolumeTool::NbCornerNodes(VolumeType type)
01818 {
01819   switch ( type ) {
01820   case TETRA     :
01821   case QUAD_TETRA: return 4;
01822   case PYRAM     :
01823   case QUAD_PYRAM: return 5;
01824   case PENTA     :
01825   case QUAD_PENTA: return 6;
01826   case HEXA      :
01827   case QUAD_HEXA : return 8;
01828   case HEX_PRISM : return 12;
01829   default:         return 0;
01830   }
01831   return 0;
01832 }
01833   // 
01834 
01835 //=======================================================================
01836 //function : GetFaceNodesIndices
01837 //purpose  : Return the array of face nodes indices
01838 //           To comfort link iteration, the array
01839 //           length == NbFaceNodes( faceIndex ) + 1 and
01840 //           the last node index == the first one.
01841 //=======================================================================
01842 
01843 const int* SMDS_VolumeTool::GetFaceNodesIndices(VolumeType type,
01844                                                 int        faceIndex,
01845                                                 bool       external)
01846 {
01847   switch ( type ) {
01848   case TETRA: return Tetra_F[ faceIndex ];
01849   case PYRAM: return Pyramid_F[ faceIndex ];
01850   case PENTA: return external ? Penta_F[ faceIndex ] : Penta_F[ faceIndex ];
01851   case HEXA:  return external ? Hexa_F[ faceIndex ] : Hexa_F[ faceIndex ];
01852   case QUAD_TETRA: return QuadTetra_F[ faceIndex ];
01853   case QUAD_PYRAM: return QuadPyram_F[ faceIndex ];
01854   case QUAD_PENTA: return external ? QuadPenta_F[ faceIndex ] : QuadPenta_F[ faceIndex ];
01855     // what about SMDSEntity_TriQuad_Hexa?
01856   case QUAD_HEXA:  return external ? QuadHexa_F[ faceIndex ] : QuadHexa_F[ faceIndex ];
01857   case HEX_PRISM:  return external ? HexPrism_F[ faceIndex ] : HexPrism_F[ faceIndex ];
01858   default:;
01859   }
01860   return 0;
01861 }
01862 
01863 //=======================================================================
01864 //function : NbFaceNodes
01865 //purpose  : Return number of nodes in the array of face nodes
01866 //=======================================================================
01867 
01868 int SMDS_VolumeTool::NbFaceNodes(VolumeType type,
01869                                  int        faceIndex )
01870 {
01871   switch ( type ) {
01872   case TETRA: return Tetra_nbN[ faceIndex ];
01873   case PYRAM: return Pyramid_nbN[ faceIndex ];
01874   case PENTA: return Penta_nbN[ faceIndex ];
01875   case HEXA:  return Hexa_nbN[ faceIndex ];
01876   case QUAD_TETRA: return QuadTetra_nbN[ faceIndex ];
01877   case QUAD_PYRAM: return QuadPyram_nbN[ faceIndex ];
01878   case QUAD_PENTA: return QuadPenta_nbN[ faceIndex ];
01879     // what about SMDSEntity_TriQuad_Hexa?
01880   case QUAD_HEXA:  return QuadHexa_nbN[ faceIndex ];
01881   case HEX_PRISM:  return HexPrism_nbN[ faceIndex ];
01882   default:;
01883   }
01884   return 0;
01885 }
01886 
01887 //=======================================================================
01888 //function : Element
01889 //purpose  : return element
01890 //=======================================================================
01891 
01892 const SMDS_MeshVolume* SMDS_VolumeTool::Element() const
01893 {
01894   return static_cast<const SMDS_MeshVolume*>( myVolume );
01895 }
01896 
01897 //=======================================================================
01898 //function : ID
01899 //purpose  : return element ID
01900 //=======================================================================
01901 
01902 int SMDS_VolumeTool::ID() const
01903 {
01904   return myVolume ? myVolume->GetID() : 0;
01905 }