Version: 6.3.1

src/Controls/SMESH_Controls.cxx

Go to the documentation of this file.
00001 // Copyright (C) 2007-2011  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 #include "SMESH_ControlsDef.hxx"
00024 
00025 #include <set>
00026 #include <limits>
00027 
00028 #include <BRepAdaptor_Surface.hxx>
00029 #include <BRepClass_FaceClassifier.hxx>
00030 #include <BRep_Tool.hxx>
00031 
00032 #include <TopAbs.hxx>
00033 #include <TopoDS.hxx>
00034 #include <TopoDS_Edge.hxx>
00035 #include <TopoDS_Face.hxx>
00036 #include <TopoDS_Shape.hxx>
00037 #include <TopoDS_Vertex.hxx>
00038 #include <TopoDS_Iterator.hxx>
00039 
00040 #include <Geom_CylindricalSurface.hxx>
00041 #include <Geom_Plane.hxx>
00042 #include <Geom_Surface.hxx>
00043 
00044 #include <Precision.hxx>
00045 #include <TColStd_MapIteratorOfMapOfInteger.hxx>
00046 #include <TColStd_MapOfInteger.hxx>
00047 #include <TColStd_SequenceOfAsciiString.hxx>
00048 #include <TColgp_Array1OfXYZ.hxx>
00049 
00050 #include <gp_Ax3.hxx>
00051 #include <gp_Cylinder.hxx>
00052 #include <gp_Dir.hxx>
00053 #include <gp_Pln.hxx>
00054 #include <gp_Pnt.hxx>
00055 #include <gp_Vec.hxx>
00056 #include <gp_XYZ.hxx>
00057 
00058 #include "SMDS_Mesh.hxx"
00059 #include "SMDS_Iterator.hxx"
00060 #include "SMDS_MeshElement.hxx"
00061 #include "SMDS_MeshNode.hxx"
00062 #include "SMDS_VolumeTool.hxx"
00063 #include "SMDS_QuadraticFaceOfNodes.hxx"
00064 #include "SMDS_QuadraticEdge.hxx"
00065 
00066 #include "SMESHDS_Mesh.hxx"
00067 #include "SMESHDS_GroupBase.hxx"
00068 
00069 #include <vtkMeshQuality.h>
00070 
00071 /*
00072                             AUXILIARY METHODS
00073 */
00074 
00075 namespace{
00076 
00077   inline gp_XYZ gpXYZ(const SMDS_MeshNode* aNode )
00078   {
00079     return gp_XYZ(aNode->X(), aNode->Y(), aNode->Z() );
00080   }
00081 
00082   inline double getAngle( const gp_XYZ& P1, const gp_XYZ& P2, const gp_XYZ& P3 )
00083   {
00084     gp_Vec v1( P1 - P2 ), v2( P3 - P2 );
00085 
00086     return v1.Magnitude() < gp::Resolution() ||
00087       v2.Magnitude() < gp::Resolution() ? 0 : v1.Angle( v2 );
00088   }
00089 
00090   inline double getArea( const gp_XYZ& P1, const gp_XYZ& P2, const gp_XYZ& P3 )
00091   {
00092     gp_Vec aVec1( P2 - P1 );
00093     gp_Vec aVec2( P3 - P1 );
00094     return ( aVec1 ^ aVec2 ).Magnitude() * 0.5;
00095   }
00096 
00097   inline double getArea( const gp_Pnt& P1, const gp_Pnt& P2, const gp_Pnt& P3 )
00098   {
00099     return getArea( P1.XYZ(), P2.XYZ(), P3.XYZ() );
00100   }
00101 
00102 
00103 
00104   inline double getDistance( const gp_XYZ& P1, const gp_XYZ& P2 )
00105   {
00106     double aDist = gp_Pnt( P1 ).Distance( gp_Pnt( P2 ) );
00107     return aDist;
00108   }
00109 
00110   int getNbMultiConnection( const SMDS_Mesh* theMesh, const int theId )
00111   {
00112     if ( theMesh == 0 )
00113       return 0;
00114 
00115     const SMDS_MeshElement* anEdge = theMesh->FindElement( theId );
00116     if ( anEdge == 0 || anEdge->GetType() != SMDSAbs_Edge/* || anEdge->NbNodes() != 2 */)
00117       return 0;
00118 
00119     // for each pair of nodes in anEdge (there are 2 pairs in a quadratic edge)
00120     // count elements containing both nodes of the pair.
00121     // Note that there may be such cases for a quadratic edge (a horizontal line):
00122     //
00123     //  Case 1          Case 2
00124     //  |     |      |        |      |
00125     //  |     |      |        |      |
00126     //  +-----+------+  +-----+------+ 
00127     //  |            |  |            |
00128     //  |            |  |            |
00129     // result sould be 2 in both cases
00130     //
00131     int aResult0 = 0, aResult1 = 0;
00132      // last node, it is a medium one in a quadratic edge
00133     const SMDS_MeshNode* aLastNode = anEdge->GetNode( anEdge->NbNodes() - 1 );
00134     const SMDS_MeshNode* aNode0 = anEdge->GetNode( 0 );
00135     const SMDS_MeshNode* aNode1 = anEdge->GetNode( 1 );
00136     if ( aNode1 == aLastNode ) aNode1 = 0;
00137 
00138     SMDS_ElemIteratorPtr anElemIter = aLastNode->GetInverseElementIterator();
00139     while( anElemIter->more() ) {
00140       const SMDS_MeshElement* anElem = anElemIter->next();
00141       if ( anElem != 0 && anElem->GetType() != SMDSAbs_Edge ) {
00142         SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
00143         while ( anIter->more() ) {
00144           if ( const SMDS_MeshElement* anElemNode = anIter->next() ) {
00145             if ( anElemNode == aNode0 ) {
00146               aResult0++;
00147               if ( !aNode1 ) break; // not a quadratic edge
00148             }
00149             else if ( anElemNode == aNode1 )
00150               aResult1++;
00151           }
00152         }
00153       }
00154     }
00155     int aResult = std::max ( aResult0, aResult1 );
00156 
00157 //     TColStd_MapOfInteger aMap;
00158 
00159 //     SMDS_ElemIteratorPtr anIter = anEdge->nodesIterator();
00160 //     if ( anIter != 0 ) {
00161 //       while( anIter->more() ) {
00162 //      const SMDS_MeshNode* aNode = (SMDS_MeshNode*)anIter->next();
00163 //      if ( aNode == 0 )
00164 //        return 0;
00165 //      SMDS_ElemIteratorPtr anElemIter = aNode->GetInverseElementIterator();
00166 //      while( anElemIter->more() ) {
00167 //        const SMDS_MeshElement* anElem = anElemIter->next();
00168 //        if ( anElem != 0 && anElem->GetType() != SMDSAbs_Edge ) {
00169 //          int anId = anElem->GetID();
00170 
00171 //          if ( anIter->more() )              // i.e. first node
00172 //            aMap.Add( anId );
00173 //          else if ( aMap.Contains( anId ) )
00174 //            aResult++;
00175 //        }
00176 //      }
00177 //       }
00178 //     }
00179 
00180     return aResult;
00181   }
00182 
00183   gp_XYZ getNormale( const SMDS_MeshFace* theFace, bool* ok=0 )
00184   {
00185     int aNbNode = theFace->NbNodes();
00186 
00187     gp_XYZ q1 = gpXYZ( theFace->GetNode(1)) - gpXYZ( theFace->GetNode(0));
00188     gp_XYZ q2 = gpXYZ( theFace->GetNode(2)) - gpXYZ( theFace->GetNode(0));
00189     gp_XYZ n  = q1 ^ q2;
00190     if ( aNbNode > 3 ) {
00191       gp_XYZ q3 = gpXYZ( theFace->GetNode(3)) - gpXYZ( theFace->GetNode(0));
00192       n += q2 ^ q3;
00193     }
00194     double len = n.Modulus();
00195     bool zeroLen = ( len <= numeric_limits<double>::min());
00196     if ( !zeroLen )
00197       n /= len;
00198 
00199     if (ok) *ok = !zeroLen;
00200 
00201     return n;
00202   }
00203 }
00204 
00205 
00206 
00207 using namespace SMESH::Controls;
00208 
00209 /*
00210  *                               FUNCTORS
00211  */
00212 
00213 /*
00214   Class       : NumericalFunctor
00215   Description : Base class for numerical functors
00216 */
00217 NumericalFunctor::NumericalFunctor():
00218   myMesh(NULL)
00219 {
00220   myPrecision = -1;
00221 }
00222 
00223 void NumericalFunctor::SetMesh( const SMDS_Mesh* theMesh )
00224 {
00225   myMesh = theMesh;
00226 }
00227 
00228 bool NumericalFunctor::GetPoints(const int theId,
00229                                  TSequenceOfXYZ& theRes ) const
00230 {
00231   theRes.clear();
00232 
00233   if ( myMesh == 0 )
00234     return false;
00235 
00236   return GetPoints( myMesh->FindElement( theId ), theRes );
00237 }
00238 
00239 bool NumericalFunctor::GetPoints(const SMDS_MeshElement* anElem,
00240                                  TSequenceOfXYZ&         theRes )
00241 {
00242   theRes.clear();
00243 
00244   if ( anElem == 0)
00245     return false;
00246 
00247   theRes.reserve( anElem->NbNodes() );
00248 
00249   // Get nodes of the element
00250   SMDS_ElemIteratorPtr anIter;
00251 
00252   if ( anElem->IsQuadratic() ) {
00253     switch ( anElem->GetType() ) {
00254     case SMDSAbs_Edge:
00255       anIter = dynamic_cast<const SMDS_VtkEdge*>
00256         (anElem)->interlacedNodesElemIterator();
00257       break;
00258     case SMDSAbs_Face:
00259       anIter = dynamic_cast<const SMDS_VtkFace*>
00260         (anElem)->interlacedNodesElemIterator();
00261       break;
00262     default:
00263       anIter = anElem->nodesIterator();
00264       //return false;
00265     }
00266   }
00267   else {
00268     anIter = anElem->nodesIterator();
00269   }
00270 
00271   if ( anIter ) {
00272     while( anIter->more() ) {
00273       if ( const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( anIter->next() ))
00274         theRes.push_back( gp_XYZ( aNode->X(), aNode->Y(), aNode->Z() ) );
00275     }
00276   }
00277 
00278   return true;
00279 }
00280 
00281 long  NumericalFunctor::GetPrecision() const
00282 {
00283   return myPrecision;
00284 }
00285 
00286 void  NumericalFunctor::SetPrecision( const long thePrecision )
00287 {
00288   myPrecision = thePrecision;
00289   myPrecisionValue = pow( 10., (double)( myPrecision ) );
00290 }
00291 
00292 double NumericalFunctor::GetValue( long theId )
00293 {
00294   double aVal = 0;
00295 
00296   myCurrElement = myMesh->FindElement( theId );
00297 
00298   TSequenceOfXYZ P;
00299   if ( GetPoints( theId, P ))
00300     aVal = Round( GetValue( P ));
00301 
00302   return aVal;
00303 }
00304 
00305 double NumericalFunctor::Round( const double & aVal )
00306 {
00307   return ( myPrecision >= 0 ) ? floor( aVal * myPrecisionValue + 0.5 ) / myPrecisionValue : aVal;
00308 }
00309 
00310 //================================================================================
00319 //================================================================================
00320 
00321 void NumericalFunctor::GetHistogram(int                  nbIntervals,
00322                                     std::vector<int>&    nbEvents,
00323                                     std::vector<double>& funValues,
00324                                     const vector<int>&   elements,
00325                                     const double*        minmax)
00326 {
00327   if ( nbIntervals < 1 ||
00328        !myMesh ||
00329        !myMesh->GetMeshInfo().NbElements( GetType() ))
00330     return;
00331   nbEvents.resize( nbIntervals, 0 );
00332   funValues.resize( nbIntervals+1 );
00333 
00334   // get all values sorted
00335   std::multiset< double > values;
00336   if ( elements.empty() )
00337   {
00338     SMDS_ElemIteratorPtr elemIt = myMesh->elementsIterator(GetType());
00339     while ( elemIt->more() )
00340       values.insert( GetValue( elemIt->next()->GetID() ));
00341   }
00342   else
00343   {
00344     vector<int>::const_iterator id = elements.begin();
00345     for ( ; id != elements.end(); ++id )
00346       values.insert( GetValue( *id ));
00347   }
00348 
00349   if ( minmax )
00350   {
00351     funValues[0] = minmax[0];
00352     funValues[nbIntervals] = minmax[1];
00353   }
00354   else
00355   {
00356     funValues[0] = *values.begin();
00357     funValues[nbIntervals] = *values.rbegin();
00358   }
00359   // case nbIntervals == 1
00360   if ( nbIntervals == 1 )
00361   {
00362     nbEvents[0] = values.size();
00363     return;
00364   }
00365   // case of 1 value
00366   if (funValues.front() == funValues.back())
00367   {
00368     nbEvents.resize( 1 );
00369     nbEvents[0] = values.size();
00370     funValues[1] = funValues.back();
00371     funValues.resize( 2 );
00372   }
00373   // generic case
00374   std::multiset< double >::iterator min = values.begin(), max;
00375   for ( int i = 0; i < nbIntervals; ++i )
00376   {
00377     // find end value of i-th interval
00378     double r = (i+1) / double( nbIntervals );
00379     funValues[i+1] = funValues.front() * (1-r) + funValues.back() * r;
00380 
00381     // count values in the i-th interval if there are any
00382     if ( min != values.end() && *min <= funValues[i+1] )
00383     {
00384       // find the first value out of the interval
00385       max = values.upper_bound( funValues[i+1] ); // max is greater than funValues[i+1], or end()
00386       nbEvents[i] = std::distance( min, max );
00387       min = max;
00388     }
00389   }
00390   // add values larger than minmax[1]
00391   nbEvents.back() += std::distance( min, values.end() );
00392 }
00393 
00394 //=======================================================================
00395 //function : GetValue
00396 //purpose  : 
00397 //=======================================================================
00398 
00399 double Volume::GetValue( long theElementId )
00400 {
00401   if ( theElementId && myMesh ) {
00402     SMDS_VolumeTool aVolumeTool;
00403     if ( aVolumeTool.Set( myMesh->FindElement( theElementId )))
00404       return aVolumeTool.GetSize();
00405   }
00406   return 0;
00407 }
00408 
00409 //=======================================================================
00410 //function : GetBadRate
00411 //purpose  : meaningless as it is not quality control functor
00412 //=======================================================================
00413 
00414 double Volume::GetBadRate( double Value, int /*nbNodes*/ ) const
00415 {
00416   return Value;
00417 }
00418 
00419 //=======================================================================
00420 //function : GetType
00421 //purpose  : 
00422 //=======================================================================
00423 
00424 SMDSAbs_ElementType Volume::GetType() const
00425 {
00426   return SMDSAbs_Volume;
00427 }
00428 
00429 
00430 /*
00431   Class       : MaxElementLength2D
00432   Description : Functor calculating maximum length of 2D element
00433 */
00434 
00435 double MaxElementLength2D::GetValue( long theElementId )
00436 {
00437   TSequenceOfXYZ P;
00438   if( GetPoints( theElementId, P ) ) {
00439     double aVal = 0;
00440     const SMDS_MeshElement* aElem = myMesh->FindElement( theElementId );
00441     SMDSAbs_ElementType aType = aElem->GetType();
00442     int len = P.size();
00443     switch( aType ) {
00444     case SMDSAbs_Face:
00445       if( len == 3 ) { // triangles
00446         double L1 = getDistance(P( 1 ),P( 2 ));
00447         double L2 = getDistance(P( 2 ),P( 3 ));
00448         double L3 = getDistance(P( 3 ),P( 1 ));
00449         aVal = Max(L1,Max(L2,L3));
00450         break;
00451       }
00452       else if( len == 4 ) { // quadrangles
00453         double L1 = getDistance(P( 1 ),P( 2 ));
00454         double L2 = getDistance(P( 2 ),P( 3 ));
00455         double L3 = getDistance(P( 3 ),P( 4 ));
00456         double L4 = getDistance(P( 4 ),P( 1 ));
00457         double D1 = getDistance(P( 1 ),P( 3 ));
00458         double D2 = getDistance(P( 2 ),P( 4 ));
00459         aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(D1,D2));
00460         break;
00461       }
00462       else if( len == 6 ) { // quadratic triangles
00463         double L1 = getDistance(P( 1 ),P( 2 )) + getDistance(P( 2 ),P( 3 ));
00464         double L2 = getDistance(P( 3 ),P( 4 )) + getDistance(P( 4 ),P( 5 ));
00465         double L3 = getDistance(P( 5 ),P( 6 )) + getDistance(P( 6 ),P( 1 ));
00466         aVal = Max(L1,Max(L2,L3));
00467         break;
00468       }
00469       else if( len == 8 ) { // quadratic quadrangles
00470         double L1 = getDistance(P( 1 ),P( 2 )) + getDistance(P( 2 ),P( 3 ));
00471         double L2 = getDistance(P( 3 ),P( 4 )) + getDistance(P( 4 ),P( 5 ));
00472         double L3 = getDistance(P( 5 ),P( 6 )) + getDistance(P( 6 ),P( 7 ));
00473         double L4 = getDistance(P( 7 ),P( 8 )) + getDistance(P( 8 ),P( 1 ));
00474         double D1 = getDistance(P( 1 ),P( 5 ));
00475         double D2 = getDistance(P( 3 ),P( 7 ));
00476         aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(D1,D2));
00477         break;
00478       }
00479     }
00480 
00481     if( myPrecision >= 0 )
00482     {
00483       double prec = pow( 10., (double)myPrecision );
00484       aVal = floor( aVal * prec + 0.5 ) / prec;
00485     }
00486     return aVal;
00487   }
00488   return 0.;
00489 }
00490 
00491 double MaxElementLength2D::GetBadRate( double Value, int /*nbNodes*/ ) const
00492 {
00493   return Value;
00494 }
00495 
00496 SMDSAbs_ElementType MaxElementLength2D::GetType() const
00497 {
00498   return SMDSAbs_Face;
00499 }
00500 
00501 /*
00502   Class       : MaxElementLength3D
00503   Description : Functor calculating maximum length of 3D element
00504 */
00505 
00506 double MaxElementLength3D::GetValue( long theElementId )
00507 {
00508   TSequenceOfXYZ P;
00509   if( GetPoints( theElementId, P ) ) {
00510     double aVal = 0;
00511     const SMDS_MeshElement* aElem = myMesh->FindElement( theElementId );
00512     SMDSAbs_ElementType aType = aElem->GetType();
00513     int len = P.size();
00514     switch( aType ) {
00515     case SMDSAbs_Volume:
00516       if( len == 4 ) { // tetras
00517         double L1 = getDistance(P( 1 ),P( 2 ));
00518         double L2 = getDistance(P( 2 ),P( 3 ));
00519         double L3 = getDistance(P( 3 ),P( 1 ));
00520         double L4 = getDistance(P( 1 ),P( 4 ));
00521         double L5 = getDistance(P( 2 ),P( 4 ));
00522         double L6 = getDistance(P( 3 ),P( 4 ));
00523         aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6));
00524         break;
00525       }
00526       else if( len == 5 ) { // pyramids
00527         double L1 = getDistance(P( 1 ),P( 2 ));
00528         double L2 = getDistance(P( 2 ),P( 3 ));
00529         double L3 = getDistance(P( 3 ),P( 4 ));
00530         double L4 = getDistance(P( 4 ),P( 1 ));
00531         double L5 = getDistance(P( 1 ),P( 5 ));
00532         double L6 = getDistance(P( 2 ),P( 5 ));
00533         double L7 = getDistance(P( 3 ),P( 5 ));
00534         double L8 = getDistance(P( 4 ),P( 5 ));
00535         aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6));
00536         aVal = Max(aVal,Max(L7,L8));
00537         break;
00538       }
00539       else if( len == 6 ) { // pentas
00540         double L1 = getDistance(P( 1 ),P( 2 ));
00541         double L2 = getDistance(P( 2 ),P( 3 ));
00542         double L3 = getDistance(P( 3 ),P( 1 ));
00543         double L4 = getDistance(P( 4 ),P( 5 ));
00544         double L5 = getDistance(P( 5 ),P( 6 ));
00545         double L6 = getDistance(P( 6 ),P( 4 ));
00546         double L7 = getDistance(P( 1 ),P( 4 ));
00547         double L8 = getDistance(P( 2 ),P( 5 ));
00548         double L9 = getDistance(P( 3 ),P( 6 ));
00549         aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6));
00550         aVal = Max(aVal,Max(Max(L7,L8),L9));
00551         break;
00552       }
00553       else if( len == 8 ) { // hexas
00554         double L1 = getDistance(P( 1 ),P( 2 ));
00555         double L2 = getDistance(P( 2 ),P( 3 ));
00556         double L3 = getDistance(P( 3 ),P( 4 ));
00557         double L4 = getDistance(P( 4 ),P( 1 ));
00558         double L5 = getDistance(P( 5 ),P( 6 ));
00559         double L6 = getDistance(P( 6 ),P( 7 ));
00560         double L7 = getDistance(P( 7 ),P( 8 ));
00561         double L8 = getDistance(P( 8 ),P( 5 ));
00562         double L9 = getDistance(P( 1 ),P( 5 ));
00563         double L10= getDistance(P( 2 ),P( 6 ));
00564         double L11= getDistance(P( 3 ),P( 7 ));
00565         double L12= getDistance(P( 4 ),P( 8 ));
00566         double D1 = getDistance(P( 1 ),P( 7 ));
00567         double D2 = getDistance(P( 2 ),P( 8 ));
00568         double D3 = getDistance(P( 3 ),P( 5 ));
00569         double D4 = getDistance(P( 4 ),P( 6 ));
00570         aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6));
00571         aVal = Max(aVal,Max(Max(L7,L8),Max(L9,L10)));
00572         aVal = Max(aVal,Max(L11,L12));
00573         aVal = Max(aVal,Max(Max(D1,D2),Max(D3,D4)));
00574         break;
00575       }
00576       else if( len == 10 ) { // quadratic tetras
00577         double L1 = getDistance(P( 1 ),P( 5 )) + getDistance(P( 5 ),P( 2 ));
00578         double L2 = getDistance(P( 2 ),P( 6 )) + getDistance(P( 6 ),P( 3 ));
00579         double L3 = getDistance(P( 3 ),P( 7 )) + getDistance(P( 7 ),P( 1 ));
00580         double L4 = getDistance(P( 1 ),P( 8 )) + getDistance(P( 8 ),P( 4 ));
00581         double L5 = getDistance(P( 2 ),P( 9 )) + getDistance(P( 9 ),P( 4 ));
00582         double L6 = getDistance(P( 3 ),P( 10 )) + getDistance(P( 10 ),P( 4 ));
00583         aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6));
00584         break;
00585       }
00586       else if( len == 13 ) { // quadratic pyramids
00587         double L1 = getDistance(P( 1 ),P( 6 )) + getDistance(P( 6 ),P( 2 ));
00588         double L2 = getDistance(P( 2 ),P( 7 )) + getDistance(P( 7 ),P( 3 ));
00589         double L3 = getDistance(P( 3 ),P( 8 )) + getDistance(P( 8 ),P( 4 ));
00590         double L4 = getDistance(P( 4 ),P( 9 )) + getDistance(P( 9 ),P( 1 ));
00591         double L5 = getDistance(P( 1 ),P( 10 )) + getDistance(P( 10 ),P( 5 ));
00592         double L6 = getDistance(P( 2 ),P( 11 )) + getDistance(P( 11 ),P( 5 ));
00593         double L7 = getDistance(P( 3 ),P( 12 )) + getDistance(P( 12 ),P( 5 ));
00594         double L8 = getDistance(P( 4 ),P( 13 )) + getDistance(P( 13 ),P( 5 ));
00595         aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6));
00596         aVal = Max(aVal,Max(L7,L8));
00597         break;
00598       }
00599       else if( len == 15 ) { // quadratic pentas
00600         double L1 = getDistance(P( 1 ),P( 7 )) + getDistance(P( 7 ),P( 2 ));
00601         double L2 = getDistance(P( 2 ),P( 8 )) + getDistance(P( 8 ),P( 3 ));
00602         double L3 = getDistance(P( 3 ),P( 9 )) + getDistance(P( 9 ),P( 1 ));
00603         double L4 = getDistance(P( 4 ),P( 10 )) + getDistance(P( 10 ),P( 5 ));
00604         double L5 = getDistance(P( 5 ),P( 11 )) + getDistance(P( 11 ),P( 6 ));
00605         double L6 = getDistance(P( 6 ),P( 12 )) + getDistance(P( 12 ),P( 4 ));
00606         double L7 = getDistance(P( 1 ),P( 13 )) + getDistance(P( 13 ),P( 4 ));
00607         double L8 = getDistance(P( 2 ),P( 14 )) + getDistance(P( 14 ),P( 5 ));
00608         double L9 = getDistance(P( 3 ),P( 15 )) + getDistance(P( 15 ),P( 6 ));
00609         aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6));
00610         aVal = Max(aVal,Max(Max(L7,L8),L9));
00611         break;
00612       }
00613       else if( len == 20 ) { // quadratic hexas
00614         double L1 = getDistance(P( 1 ),P( 9 )) + getDistance(P( 9 ),P( 2 ));
00615         double L2 = getDistance(P( 2 ),P( 10 )) + getDistance(P( 10 ),P( 3 ));
00616         double L3 = getDistance(P( 3 ),P( 11 )) + getDistance(P( 11 ),P( 4 ));
00617         double L4 = getDistance(P( 4 ),P( 12 )) + getDistance(P( 12 ),P( 1 ));
00618         double L5 = getDistance(P( 5 ),P( 13 )) + getDistance(P( 13 ),P( 6 ));
00619         double L6 = getDistance(P( 6 ),P( 14 )) + getDistance(P( 14 ),P( 7 ));
00620         double L7 = getDistance(P( 7 ),P( 15 )) + getDistance(P( 15 ),P( 8 ));
00621         double L8 = getDistance(P( 8 ),P( 16 )) + getDistance(P( 16 ),P( 5 ));
00622         double L9 = getDistance(P( 1 ),P( 17 )) + getDistance(P( 17 ),P( 5 ));
00623         double L10= getDistance(P( 2 ),P( 18 )) + getDistance(P( 18 ),P( 6 ));
00624         double L11= getDistance(P( 3 ),P( 19 )) + getDistance(P( 19 ),P( 7 ));
00625         double L12= getDistance(P( 4 ),P( 20 )) + getDistance(P( 20 ),P( 8 ));
00626         double D1 = getDistance(P( 1 ),P( 7 ));
00627         double D2 = getDistance(P( 2 ),P( 8 ));
00628         double D3 = getDistance(P( 3 ),P( 5 ));
00629         double D4 = getDistance(P( 4 ),P( 6 ));
00630         aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6));
00631         aVal = Max(aVal,Max(Max(L7,L8),Max(L9,L10)));
00632         aVal = Max(aVal,Max(L11,L12));
00633         aVal = Max(aVal,Max(Max(D1,D2),Max(D3,D4)));
00634         break;
00635       }
00636       else if( len > 1 && aElem->IsPoly() ) { // polys
00637         // get the maximum distance between all pairs of nodes
00638         for( int i = 1; i <= len; i++ ) {
00639           for( int j = 1; j <= len; j++ ) {
00640             if( j > i ) { // optimization of the loop
00641               double D = getDistance( P(i), P(j) );
00642               aVal = Max( aVal, D );
00643             }
00644           }
00645         }
00646       }
00647     }
00648 
00649     if( myPrecision >= 0 )
00650     {
00651       double prec = pow( 10., (double)myPrecision );
00652       aVal = floor( aVal * prec + 0.5 ) / prec;
00653     }
00654     return aVal;
00655   }
00656   return 0.;
00657 }
00658 
00659 double MaxElementLength3D::GetBadRate( double Value, int /*nbNodes*/ ) const
00660 {
00661   return Value;
00662 }
00663 
00664 SMDSAbs_ElementType MaxElementLength3D::GetType() const
00665 {
00666   return SMDSAbs_Volume;
00667 }
00668 
00669 
00670 /*
00671   Class       : MinimumAngle
00672   Description : Functor for calculation of minimum angle
00673 */
00674 
00675 double MinimumAngle::GetValue( const TSequenceOfXYZ& P )
00676 {
00677   double aMin;
00678 
00679   if (P.size() <3)
00680     return 0.;
00681 
00682   aMin = getAngle(P( P.size() ), P( 1 ), P( 2 ));
00683   aMin = Min(aMin,getAngle(P( P.size()-1 ), P( P.size() ), P( 1 )));
00684 
00685   for (int i=2; i<P.size();i++){
00686       double A0 = getAngle( P( i-1 ), P( i ), P( i+1 ) );
00687     aMin = Min(aMin,A0);
00688   }
00689 
00690   return aMin * 180.0 / PI;
00691 }
00692 
00693 double MinimumAngle::GetBadRate( double Value, int nbNodes ) const
00694 {
00695   //const double aBestAngle = PI / nbNodes;
00696   const double aBestAngle = 180.0 - ( 360.0 / double(nbNodes) );
00697   return ( fabs( aBestAngle - Value ));
00698 }
00699 
00700 SMDSAbs_ElementType MinimumAngle::GetType() const
00701 {
00702   return SMDSAbs_Face;
00703 }
00704 
00705 
00706 /*
00707   Class       : AspectRatio
00708   Description : Functor for calculating aspect ratio
00709 */
00710 double AspectRatio::GetValue( const TSequenceOfXYZ& P )
00711 {
00712   // According to "Mesh quality control" by Nadir Bouhamau referring to
00713   // Pascal Jean Frey and Paul-Louis George. Maillages, applications aux elements finis.
00714   // Hermes Science publications, Paris 1999 ISBN 2-7462-0024-4
00715   // PAL10872
00716 
00717   int nbNodes = P.size();
00718 
00719   if ( nbNodes < 3 )
00720     return 0;
00721 
00722   // Compute aspect ratio
00723 
00724   if ( nbNodes == 3 ) {
00725     // Compute lengths of the sides
00726     std::vector< double > aLen (nbNodes);
00727     for ( int i = 0; i < nbNodes - 1; i++ )
00728       aLen[ i ] = getDistance( P( i + 1 ), P( i + 2 ) );
00729     aLen[ nbNodes - 1 ] = getDistance( P( 1 ), P( nbNodes ) );
00730     // Q = alfa * h * p / S, where
00731     //
00732     // alfa = sqrt( 3 ) / 6
00733     // h - length of the longest edge
00734     // p - half perimeter
00735     // S - triangle surface
00736     const double alfa = sqrt( 3. ) / 6.;
00737     double maxLen = Max( aLen[ 0 ], Max( aLen[ 1 ], aLen[ 2 ] ) );
00738     double half_perimeter = ( aLen[0] + aLen[1] + aLen[2] ) / 2.;
00739     double anArea = getArea( P( 1 ), P( 2 ), P( 3 ) );
00740     if ( anArea <= Precision::Confusion() )
00741       return 0.;
00742     return alfa * maxLen * half_perimeter / anArea;
00743   }
00744   else if ( nbNodes == 6 ) { // quadratic triangles
00745     // Compute lengths of the sides
00746     std::vector< double > aLen (3);
00747     aLen[0] = getDistance( P(1), P(3) );
00748     aLen[1] = getDistance( P(3), P(5) );
00749     aLen[2] = getDistance( P(5), P(1) );
00750     // Q = alfa * h * p / S, where
00751     //
00752     // alfa = sqrt( 3 ) / 6
00753     // h - length of the longest edge
00754     // p - half perimeter
00755     // S - triangle surface
00756     const double alfa = sqrt( 3. ) / 6.;
00757     double maxLen = Max( aLen[ 0 ], Max( aLen[ 1 ], aLen[ 2 ] ) );
00758     double half_perimeter = ( aLen[0] + aLen[1] + aLen[2] ) / 2.;
00759     double anArea = getArea( P(1), P(3), P(5) );
00760     if ( anArea <= Precision::Confusion() )
00761       return 0.;
00762     return alfa * maxLen * half_perimeter / anArea;
00763   }
00764   else if( nbNodes == 4 ) { // quadrangle
00765     // Compute lengths of the sides
00766     std::vector< double > aLen (4);
00767     aLen[0] = getDistance( P(1), P(2) );
00768     aLen[1] = getDistance( P(2), P(3) );
00769     aLen[2] = getDistance( P(3), P(4) );
00770     aLen[3] = getDistance( P(4), P(1) );
00771     // Compute lengths of the diagonals
00772     std::vector< double > aDia (2);
00773     aDia[0] = getDistance( P(1), P(3) );
00774     aDia[1] = getDistance( P(2), P(4) );
00775     // Compute areas of all triangles which can be built
00776     // taking three nodes of the quadrangle
00777     std::vector< double > anArea (4);
00778     anArea[0] = getArea( P(1), P(2), P(3) );
00779     anArea[1] = getArea( P(1), P(2), P(4) );
00780     anArea[2] = getArea( P(1), P(3), P(4) );
00781     anArea[3] = getArea( P(2), P(3), P(4) );
00782     // Q = alpha * L * C1 / C2, where
00783     //
00784     // alpha = sqrt( 1/32 )
00785     // L = max( L1, L2, L3, L4, D1, D2 )
00786     // C1 = sqrt( ( L1^2 + L1^2 + L1^2 + L1^2 ) / 4 )
00787     // C2 = min( S1, S2, S3, S4 )
00788     // Li - lengths of the edges
00789     // Di - lengths of the diagonals
00790     // Si - areas of the triangles
00791     const double alpha = sqrt( 1 / 32. );
00792     double L = Max( aLen[ 0 ],
00793                  Max( aLen[ 1 ],
00794                    Max( aLen[ 2 ],
00795                      Max( aLen[ 3 ],
00796                        Max( aDia[ 0 ], aDia[ 1 ] ) ) ) ) );
00797     double C1 = sqrt( ( aLen[0] * aLen[0] +
00798                         aLen[1] * aLen[1] +
00799                         aLen[2] * aLen[2] +
00800                         aLen[3] * aLen[3] ) / 4. );
00801     double C2 = Min( anArea[ 0 ],
00802                   Min( anArea[ 1 ],
00803                     Min( anArea[ 2 ], anArea[ 3 ] ) ) );
00804     if ( C2 <= Precision::Confusion() )
00805       return 0.;
00806     return alpha * L * C1 / C2;
00807   }
00808   else if( nbNodes == 8 ){ // nbNodes==8 - quadratic quadrangle
00809     // Compute lengths of the sides
00810     std::vector< double > aLen (4);
00811     aLen[0] = getDistance( P(1), P(3) );
00812     aLen[1] = getDistance( P(3), P(5) );
00813     aLen[2] = getDistance( P(5), P(7) );
00814     aLen[3] = getDistance( P(7), P(1) );
00815     // Compute lengths of the diagonals
00816     std::vector< double > aDia (2);
00817     aDia[0] = getDistance( P(1), P(5) );
00818     aDia[1] = getDistance( P(3), P(7) );
00819     // Compute areas of all triangles which can be built
00820     // taking three nodes of the quadrangle
00821     std::vector< double > anArea (4);
00822     anArea[0] = getArea( P(1), P(3), P(5) );
00823     anArea[1] = getArea( P(1), P(3), P(7) );
00824     anArea[2] = getArea( P(1), P(5), P(7) );
00825     anArea[3] = getArea( P(3), P(5), P(7) );
00826     // Q = alpha * L * C1 / C2, where
00827     //
00828     // alpha = sqrt( 1/32 )
00829     // L = max( L1, L2, L3, L4, D1, D2 )
00830     // C1 = sqrt( ( L1^2 + L1^2 + L1^2 + L1^2 ) / 4 )
00831     // C2 = min( S1, S2, S3, S4 )
00832     // Li - lengths of the edges
00833     // Di - lengths of the diagonals
00834     // Si - areas of the triangles
00835     const double alpha = sqrt( 1 / 32. );
00836     double L = Max( aLen[ 0 ],
00837                  Max( aLen[ 1 ],
00838                    Max( aLen[ 2 ],
00839                      Max( aLen[ 3 ],
00840                        Max( aDia[ 0 ], aDia[ 1 ] ) ) ) ) );
00841     double C1 = sqrt( ( aLen[0] * aLen[0] +
00842                         aLen[1] * aLen[1] +
00843                         aLen[2] * aLen[2] +
00844                         aLen[3] * aLen[3] ) / 4. );
00845     double C2 = Min( anArea[ 0 ],
00846                   Min( anArea[ 1 ],
00847                     Min( anArea[ 2 ], anArea[ 3 ] ) ) );
00848     if ( C2 <= Precision::Confusion() )
00849       return 0.;
00850     return alpha * L * C1 / C2;
00851   }
00852   return 0;
00853 }
00854 
00855 double AspectRatio::GetBadRate( double Value, int /*nbNodes*/ ) const
00856 {
00857   // the aspect ratio is in the range [1.0,infinity]
00858   // 1.0 = good
00859   // infinity = bad
00860   return Value / 1000.;
00861 }
00862 
00863 SMDSAbs_ElementType AspectRatio::GetType() const
00864 {
00865   return SMDSAbs_Face;
00866 }
00867 
00868 
00869 /*
00870   Class       : AspectRatio3D
00871   Description : Functor for calculating aspect ratio
00872 */
00873 namespace{
00874 
00875   inline double getHalfPerimeter(double theTria[3]){
00876     return (theTria[0] + theTria[1] + theTria[2])/2.0;
00877   }
00878 
00879   inline double getArea(double theHalfPerim, double theTria[3]){
00880     return sqrt(theHalfPerim*
00881                 (theHalfPerim-theTria[0])*
00882                 (theHalfPerim-theTria[1])*
00883                 (theHalfPerim-theTria[2]));
00884   }
00885 
00886   inline double getVolume(double theLen[6]){
00887     double a2 = theLen[0]*theLen[0];
00888     double b2 = theLen[1]*theLen[1];
00889     double c2 = theLen[2]*theLen[2];
00890     double d2 = theLen[3]*theLen[3];
00891     double e2 = theLen[4]*theLen[4];
00892     double f2 = theLen[5]*theLen[5];
00893     double P = 4.0*a2*b2*d2;
00894     double Q = a2*(b2+d2-e2)-b2*(a2+d2-f2)-d2*(a2+b2-c2);
00895     double R = (b2+d2-e2)*(a2+d2-f2)*(a2+d2-f2);
00896     return sqrt(P-Q+R)/12.0;
00897   }
00898 
00899   inline double getVolume2(double theLen[6]){
00900     double a2 = theLen[0]*theLen[0];
00901     double b2 = theLen[1]*theLen[1];
00902     double c2 = theLen[2]*theLen[2];
00903     double d2 = theLen[3]*theLen[3];
00904     double e2 = theLen[4]*theLen[4];
00905     double f2 = theLen[5]*theLen[5];
00906 
00907     double P = a2*e2*(b2+c2+d2+f2-a2-e2);
00908     double Q = b2*f2*(a2+c2+d2+e2-b2-f2);
00909     double R = c2*d2*(a2+b2+e2+f2-c2-d2);
00910     double S = a2*b2*d2+b2*c2*e2+a2*c2*f2+d2*e2*f2;
00911 
00912     return sqrt(P+Q+R-S)/12.0;
00913   }
00914 
00915   inline double getVolume(const TSequenceOfXYZ& P){
00916     gp_Vec aVec1( P( 2 ) - P( 1 ) );
00917     gp_Vec aVec2( P( 3 ) - P( 1 ) );
00918     gp_Vec aVec3( P( 4 ) - P( 1 ) );
00919     gp_Vec anAreaVec( aVec1 ^ aVec2 );
00920     return fabs(aVec3 * anAreaVec) / 6.0;
00921   }
00922 
00923   inline double getMaxHeight(double theLen[6])
00924   {
00925     double aHeight = std::max(theLen[0],theLen[1]);
00926     aHeight = std::max(aHeight,theLen[2]);
00927     aHeight = std::max(aHeight,theLen[3]);
00928     aHeight = std::max(aHeight,theLen[4]);
00929     aHeight = std::max(aHeight,theLen[5]);
00930     return aHeight;
00931   }
00932 
00933 }
00934 
00935 double AspectRatio3D::GetValue( long theId )
00936 {
00937   double aVal = 0;
00938   myCurrElement = myMesh->FindElement( theId );
00939   if ( myCurrElement && myCurrElement->GetVtkType() == VTK_TETRA )
00940   {
00941     // Action from CoTech | ACTION 31.3:
00942     // EURIWARE BO: Homogenize the formulas used to calculate the Controls in SMESH to fit with
00943     // those of ParaView. The library used by ParaView for those calculations can be reused in SMESH.
00944     vtkUnstructuredGrid* grid = SMDS_Mesh::_meshList[myCurrElement->getMeshId()]->getGrid();
00945     if ( vtkCell* avtkCell = grid->GetCell( myCurrElement->getVtkId() ))
00946       aVal = Round( vtkMeshQuality::TetAspectRatio( avtkCell ));
00947   }
00948   else
00949   {
00950     TSequenceOfXYZ P;
00951     if ( GetPoints( myCurrElement, P ))
00952       aVal = Round( GetValue( P ));
00953   }
00954   return aVal;
00955 }
00956 
00957 double AspectRatio3D::GetValue( const TSequenceOfXYZ& P )
00958 {
00959   double aQuality = 0.0;
00960   if(myCurrElement->IsPoly()) return aQuality;
00961 
00962   int nbNodes = P.size();
00963 
00964   if(myCurrElement->IsQuadratic()) {
00965     if(nbNodes==10) nbNodes=4; // quadratic tetrahedron
00966     else if(nbNodes==13) nbNodes=5; // quadratic pyramid
00967     else if(nbNodes==15) nbNodes=6; // quadratic pentahedron
00968     else if(nbNodes==20) nbNodes=8; // quadratic hexahedron
00969     else return aQuality;
00970   }
00971 
00972   switch(nbNodes){
00973   case 4:{
00974     double aLen[6] = {
00975       getDistance(P( 1 ),P( 2 )), // a
00976       getDistance(P( 2 ),P( 3 )), // b
00977       getDistance(P( 3 ),P( 1 )), // c
00978       getDistance(P( 2 ),P( 4 )), // d
00979       getDistance(P( 3 ),P( 4 )), // e
00980       getDistance(P( 1 ),P( 4 ))  // f
00981     };
00982     double aTria[4][3] = {
00983       {aLen[0],aLen[1],aLen[2]}, // abc
00984       {aLen[0],aLen[3],aLen[5]}, // adf
00985       {aLen[1],aLen[3],aLen[4]}, // bde
00986       {aLen[2],aLen[4],aLen[5]}  // cef
00987     };
00988     double aSumArea = 0.0;
00989     double aHalfPerimeter = getHalfPerimeter(aTria[0]);
00990     double anArea = getArea(aHalfPerimeter,aTria[0]);
00991     aSumArea += anArea;
00992     aHalfPerimeter = getHalfPerimeter(aTria[1]);
00993     anArea = getArea(aHalfPerimeter,aTria[1]);
00994     aSumArea += anArea;
00995     aHalfPerimeter = getHalfPerimeter(aTria[2]);
00996     anArea = getArea(aHalfPerimeter,aTria[2]);
00997     aSumArea += anArea;
00998     aHalfPerimeter = getHalfPerimeter(aTria[3]);
00999     anArea = getArea(aHalfPerimeter,aTria[3]);
01000     aSumArea += anArea;
01001     double aVolume = getVolume(P);
01002     //double aVolume = getVolume(aLen);
01003     double aHeight = getMaxHeight(aLen);
01004     static double aCoeff = sqrt(2.0)/12.0;
01005     if ( aVolume > DBL_MIN )
01006       aQuality = aCoeff*aHeight*aSumArea/aVolume;
01007     break;
01008   }
01009   case 5:{
01010     {
01011       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 3 ),P( 5 )};
01012       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
01013     }
01014     {
01015       gp_XYZ aXYZ[4] = {P( 1 ),P( 3 ),P( 4 ),P( 5 )};
01016       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
01017     }
01018     {
01019       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 4 ),P( 5 )};
01020       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
01021     }
01022     {
01023       gp_XYZ aXYZ[4] = {P( 2 ),P( 3 ),P( 4 ),P( 5 )};
01024       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
01025     }
01026     break;
01027   }
01028   case 6:{
01029     {
01030       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 4 ),P( 6 )};
01031       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
01032     }
01033     {
01034       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 4 ),P( 3 )};
01035       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
01036     }
01037     {
01038       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 5 ),P( 6 )};
01039       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
01040     }
01041     {
01042       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 5 ),P( 3 )};
01043       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
01044     }
01045     {
01046       gp_XYZ aXYZ[4] = {P( 2 ),P( 5 ),P( 4 ),P( 6 )};
01047       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
01048     }
01049     {
01050       gp_XYZ aXYZ[4] = {P( 2 ),P( 5 ),P( 4 ),P( 3 )};
01051       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
01052     }
01053     break;
01054   }
01055   case 8:{
01056     {
01057       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 5 ),P( 3 )};
01058       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
01059     }
01060     {
01061       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 5 ),P( 4 )};
01062       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
01063     }
01064     {
01065       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 5 ),P( 7 )};
01066       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
01067     }
01068     {
01069       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 5 ),P( 8 )};
01070       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
01071     }
01072     {
01073       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 6 ),P( 3 )};
01074       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
01075     }
01076     {
01077       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 6 ),P( 4 )};
01078       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
01079     }
01080     {
01081       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 6 ),P( 7 )};
01082       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
01083     }
01084     {
01085       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 6 ),P( 8 )};
01086       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
01087     }
01088     {
01089       gp_XYZ aXYZ[4] = {P( 2 ),P( 6 ),P( 5 ),P( 3 )};
01090       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
01091     }
01092     {
01093       gp_XYZ aXYZ[4] = {P( 2 ),P( 6 ),P( 5 ),P( 4 )};
01094       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
01095     }
01096     {
01097       gp_XYZ aXYZ[4] = {P( 2 ),P( 6 ),P( 5 ),P( 7 )};
01098       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
01099     }
01100     {
01101       gp_XYZ aXYZ[4] = {P( 2 ),P( 6 ),P( 5 ),P( 8 )};
01102       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
01103     }
01104     {
01105       gp_XYZ aXYZ[4] = {P( 3 ),P( 4 ),P( 8 ),P( 1 )};
01106       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
01107     }
01108     {
01109       gp_XYZ aXYZ[4] = {P( 3 ),P( 4 ),P( 8 ),P( 2 )};
01110       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
01111     }
01112     {
01113       gp_XYZ aXYZ[4] = {P( 3 ),P( 4 ),P( 8 ),P( 5 )};
01114       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
01115     }
01116     {
01117       gp_XYZ aXYZ[4] = {P( 3 ),P( 4 ),P( 8 ),P( 6 )};
01118       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
01119     }
01120     {
01121       gp_XYZ aXYZ[4] = {P( 3 ),P( 4 ),P( 7 ),P( 1 )};
01122       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
01123     }
01124     {
01125       gp_XYZ aXYZ[4] = {P( 3 ),P( 4 ),P( 7 ),P( 2 )};
01126       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
01127     }
01128     {
01129       gp_XYZ aXYZ[4] = {P( 3 ),P( 4 ),P( 7 ),P( 5 )};
01130       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
01131     }
01132     {
01133       gp_XYZ aXYZ[4] = {P( 3 ),P( 4 ),P( 7 ),P( 6 )};
01134       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
01135     }
01136     {
01137       gp_XYZ aXYZ[4] = {P( 4 ),P( 8 ),P( 7 ),P( 1 )};
01138       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
01139     }
01140     {
01141       gp_XYZ aXYZ[4] = {P( 4 ),P( 8 ),P( 7 ),P( 2 )};
01142       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
01143     }
01144     {
01145       gp_XYZ aXYZ[4] = {P( 4 ),P( 8 ),P( 7 ),P( 5 )};
01146       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
01147     }
01148     {
01149       gp_XYZ aXYZ[4] = {P( 4 ),P( 8 ),P( 7 ),P( 6 )};
01150       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
01151     }
01152     {
01153       gp_XYZ aXYZ[4] = {P( 4 ),P( 8 ),P( 7 ),P( 2 )};
01154       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
01155     }
01156     {
01157       gp_XYZ aXYZ[4] = {P( 4 ),P( 5 ),P( 8 ),P( 2 )};
01158       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
01159     }
01160     {
01161       gp_XYZ aXYZ[4] = {P( 1 ),P( 4 ),P( 5 ),P( 3 )};
01162       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
01163     }
01164     {
01165       gp_XYZ aXYZ[4] = {P( 3 ),P( 6 ),P( 7 ),P( 1 )};
01166       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
01167     }
01168     {
01169       gp_XYZ aXYZ[4] = {P( 2 ),P( 3 ),P( 6 ),P( 4 )};
01170       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
01171     }
01172     {
01173       gp_XYZ aXYZ[4] = {P( 5 ),P( 6 ),P( 8 ),P( 3 )};
01174       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
01175     }
01176     {
01177       gp_XYZ aXYZ[4] = {P( 7 ),P( 8 ),P( 6 ),P( 1 )};
01178       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
01179     }
01180     {
01181       gp_XYZ aXYZ[4] = {P( 1 ),P( 2 ),P( 4 ),P( 7 )};
01182       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
01183     }
01184     {
01185       gp_XYZ aXYZ[4] = {P( 3 ),P( 4 ),P( 2 ),P( 5 )};
01186       aQuality = std::max(GetValue(TSequenceOfXYZ(&aXYZ[0],&aXYZ[4])),aQuality);
01187     }
01188     break;
01189   }
01190   }
01191   if ( nbNodes > 4 ) {
01192     // avaluate aspect ratio of quadranle faces
01193     AspectRatio aspect2D;
01194     SMDS_VolumeTool::VolumeType type = SMDS_VolumeTool::GetType( nbNodes );
01195     int nbFaces = SMDS_VolumeTool::NbFaces( type );
01196     TSequenceOfXYZ points(4);
01197     for ( int i = 0; i < nbFaces; ++i ) { // loop on faces of a volume
01198       if ( SMDS_VolumeTool::NbFaceNodes( type, i ) != 4 )
01199         continue;
01200       const int* pInd = SMDS_VolumeTool::GetFaceNodesIndices( type, i, true );
01201       for ( int p = 0; p < 4; ++p ) // loop on nodes of a quadranle face
01202         points( p + 1 ) = P( pInd[ p ] + 1 );
01203       aQuality = std::max( aQuality, aspect2D.GetValue( points ));
01204     }
01205   }
01206   return aQuality;
01207 }
01208 
01209 double AspectRatio3D::GetBadRate( double Value, int /*nbNodes*/ ) const
01210 {
01211   // the aspect ratio is in the range [1.0,infinity]
01212   // 1.0 = good
01213   // infinity = bad
01214   return Value / 1000.;
01215 }
01216 
01217 SMDSAbs_ElementType AspectRatio3D::GetType() const
01218 {
01219   return SMDSAbs_Volume;
01220 }
01221 
01222 
01223 /*
01224   Class       : Warping
01225   Description : Functor for calculating warping
01226 */
01227 double Warping::GetValue( const TSequenceOfXYZ& P )
01228 {
01229   if ( P.size() != 4 )
01230     return 0;
01231 
01232   gp_XYZ G = ( P( 1 ) + P( 2 ) + P( 3 ) + P( 4 ) ) / 4.;
01233 
01234   double A1 = ComputeA( P( 1 ), P( 2 ), P( 3 ), G );
01235   double A2 = ComputeA( P( 2 ), P( 3 ), P( 4 ), G );
01236   double A3 = ComputeA( P( 3 ), P( 4 ), P( 1 ), G );
01237   double A4 = ComputeA( P( 4 ), P( 1 ), P( 2 ), G );
01238 
01239   return Max( Max( A1, A2 ), Max( A3, A4 ) );
01240 }
01241 
01242 double Warping::ComputeA( const gp_XYZ& thePnt1,
01243                           const gp_XYZ& thePnt2,
01244                           const gp_XYZ& thePnt3,
01245                           const gp_XYZ& theG ) const
01246 {
01247   double aLen1 = gp_Pnt( thePnt1 ).Distance( gp_Pnt( thePnt2 ) );
01248   double aLen2 = gp_Pnt( thePnt2 ).Distance( gp_Pnt( thePnt3 ) );
01249   double L = Min( aLen1, aLen2 ) * 0.5;
01250   if ( L < Precision::Confusion())
01251     return 0.;
01252 
01253   gp_XYZ GI = ( thePnt2 + thePnt1 ) / 2. - theG;
01254   gp_XYZ GJ = ( thePnt3 + thePnt2 ) / 2. - theG;
01255   gp_XYZ N  = GI.Crossed( GJ );
01256 
01257   if ( N.Modulus() < gp::Resolution() )
01258     return PI / 2;
01259 
01260   N.Normalize();
01261 
01262   double H = ( thePnt2 - theG ).Dot( N );
01263   return asin( fabs( H / L ) ) * 180. / PI;
01264 }
01265 
01266 double Warping::GetBadRate( double Value, int /*nbNodes*/ ) const
01267 {
01268   // the warp is in the range [0.0,PI/2]
01269   // 0.0 = good (no warp)
01270   // PI/2 = bad  (face pliee)
01271   return Value;
01272 }
01273 
01274 SMDSAbs_ElementType Warping::GetType() const
01275 {
01276   return SMDSAbs_Face;
01277 }
01278 
01279 
01280 /*
01281   Class       : Taper
01282   Description : Functor for calculating taper
01283 */
01284 double Taper::GetValue( const TSequenceOfXYZ& P )
01285 {
01286   if ( P.size() != 4 )
01287     return 0.;
01288 
01289   // Compute taper
01290   double J1 = getArea( P( 4 ), P( 1 ), P( 2 ) ) / 2.;
01291   double J2 = getArea( P( 3 ), P( 1 ), P( 2 ) ) / 2.;
01292   double J3 = getArea( P( 2 ), P( 3 ), P( 4 ) ) / 2.;
01293   double J4 = getArea( P( 3 ), P( 4 ), P( 1 ) ) / 2.;
01294 
01295   double JA = 0.25 * ( J1 + J2 + J3 + J4 );
01296   if ( JA <= Precision::Confusion() )
01297     return 0.;
01298 
01299   double T1 = fabs( ( J1 - JA ) / JA );
01300   double T2 = fabs( ( J2 - JA ) / JA );
01301   double T3 = fabs( ( J3 - JA ) / JA );
01302   double T4 = fabs( ( J4 - JA ) / JA );
01303 
01304   return Max( Max( T1, T2 ), Max( T3, T4 ) );
01305 }
01306 
01307 double Taper::GetBadRate( double Value, int /*nbNodes*/ ) const
01308 {
01309   // the taper is in the range [0.0,1.0]
01310   // 0.0  = good (no taper)
01311   // 1.0 = bad  (les cotes opposes sont allignes)
01312   return Value;
01313 }
01314 
01315 SMDSAbs_ElementType Taper::GetType() const
01316 {
01317   return SMDSAbs_Face;
01318 }
01319 
01320 
01321 /*
01322   Class       : Skew
01323   Description : Functor for calculating skew in degrees
01324 */
01325 static inline double skewAngle( const gp_XYZ& p1, const gp_XYZ& p2, const gp_XYZ& p3 )
01326 {
01327   gp_XYZ p12 = ( p2 + p1 ) / 2.;
01328   gp_XYZ p23 = ( p3 + p2 ) / 2.;
01329   gp_XYZ p31 = ( p3 + p1 ) / 2.;
01330 
01331   gp_Vec v1( p31 - p2 ), v2( p12 - p23 );
01332 
01333   return v1.Magnitude() < gp::Resolution() || v2.Magnitude() < gp::Resolution() ? 0. : v1.Angle( v2 );
01334 }
01335 
01336 double Skew::GetValue( const TSequenceOfXYZ& P )
01337 {
01338   if ( P.size() != 3 && P.size() != 4 )
01339     return 0.;
01340 
01341   // Compute skew
01342   static double PI2 = PI / 2.;
01343   if ( P.size() == 3 )
01344   {
01345     double A0 = fabs( PI2 - skewAngle( P( 3 ), P( 1 ), P( 2 ) ) );
01346     double A1 = fabs( PI2 - skewAngle( P( 1 ), P( 2 ), P( 3 ) ) );
01347     double A2 = fabs( PI2 - skewAngle( P( 2 ), P( 3 ), P( 1 ) ) );
01348 
01349     return Max( A0, Max( A1, A2 ) ) * 180. / PI;
01350   }
01351   else
01352   {
01353     gp_XYZ p12 = ( P( 1 ) + P( 2 ) ) / 2.;
01354     gp_XYZ p23 = ( P( 2 ) + P( 3 ) ) / 2.;
01355     gp_XYZ p34 = ( P( 3 ) + P( 4 ) ) / 2.;
01356     gp_XYZ p41 = ( P( 4 ) + P( 1 ) ) / 2.;
01357 
01358     gp_Vec v1( p34 - p12 ), v2( p23 - p41 );
01359     double A = v1.Magnitude() <= gp::Resolution() || v2.Magnitude() <= gp::Resolution()
01360       ? 0. : fabs( PI2 - v1.Angle( v2 ) );
01361 
01362     //BUG SWP12743
01363     if ( A < Precision::Angular() )
01364       return 0.;
01365 
01366     return A * 180. / PI;
01367   }
01368 }
01369 
01370 double Skew::GetBadRate( double Value, int /*nbNodes*/ ) const
01371 {
01372   // the skew is in the range [0.0,PI/2].
01373   // 0.0 = good
01374   // PI/2 = bad
01375   return Value;
01376 }
01377 
01378 SMDSAbs_ElementType Skew::GetType() const
01379 {
01380   return SMDSAbs_Face;
01381 }
01382 
01383 
01384 /*
01385   Class       : Area
01386   Description : Functor for calculating area
01387 */
01388 double Area::GetValue( const TSequenceOfXYZ& P )
01389 {
01390   double val = 0.0;
01391   if ( P.size() > 2 ) {
01392     gp_Vec aVec1( P(2) - P(1) );
01393     gp_Vec aVec2( P(3) - P(1) );
01394     gp_Vec SumVec = aVec1 ^ aVec2;
01395     for (int i=4; i<=P.size(); i++) {
01396       gp_Vec aVec1( P(i-1) - P(1) );
01397       gp_Vec aVec2( P(i) - P(1) );
01398       gp_Vec tmp = aVec1 ^ aVec2;
01399       SumVec.Add(tmp);
01400     }
01401     val = SumVec.Magnitude() * 0.5;
01402   }
01403   return val;
01404 }
01405 
01406 double Area::GetBadRate( double Value, int /*nbNodes*/ ) const
01407 {
01408   // meaningless as it is not a quality control functor
01409   return Value;
01410 }
01411 
01412 SMDSAbs_ElementType Area::GetType() const
01413 {
01414   return SMDSAbs_Face;
01415 }
01416 
01417 
01418 /*
01419   Class       : Length
01420   Description : Functor for calculating length off edge
01421 */
01422 double Length::GetValue( const TSequenceOfXYZ& P )
01423 {
01424   switch ( P.size() ) {
01425   case 2:  return getDistance( P( 1 ), P( 2 ) );
01426   case 3:  return getDistance( P( 1 ), P( 2 ) ) + getDistance( P( 2 ), P( 3 ) );
01427   default: return 0.;
01428   }
01429 }
01430 
01431 double Length::GetBadRate( double Value, int /*nbNodes*/ ) const
01432 {
01433   // meaningless as it is not quality control functor
01434   return Value;
01435 }
01436 
01437 SMDSAbs_ElementType Length::GetType() const
01438 {
01439   return SMDSAbs_Edge;
01440 }
01441 
01442 /*
01443   Class       : Length2D
01444   Description : Functor for calculating length of edge
01445 */
01446 
01447 double Length2D::GetValue( long theElementId)
01448 {
01449   TSequenceOfXYZ P;
01450 
01451   //cout<<"Length2D::GetValue"<<endl;
01452   if (GetPoints(theElementId,P)){
01453     //for(int jj=1; jj<=P.size(); jj++)
01454     //  cout<<"jj="<<jj<<" P("<<P(jj).X()<<","<<P(jj).Y()<<","<<P(jj).Z()<<")"<<endl;
01455 
01456     double  aVal;// = GetValue( P );
01457     const SMDS_MeshElement* aElem = myMesh->FindElement( theElementId );
01458     SMDSAbs_ElementType aType = aElem->GetType();
01459 
01460     int len = P.size();
01461 
01462     switch (aType){
01463     case SMDSAbs_All:
01464     case SMDSAbs_Node:
01465     case SMDSAbs_Edge:
01466       if (len == 2){
01467         aVal = getDistance( P( 1 ), P( 2 ) );
01468         break;
01469       }
01470       else if (len == 3){ // quadratic edge
01471         aVal = getDistance(P( 1 ),P( 3 )) + getDistance(P( 3 ),P( 2 ));
01472         break;
01473       }
01474     case SMDSAbs_Face:
01475       if (len == 3){ // triangles
01476         double L1 = getDistance(P( 1 ),P( 2 ));
01477         double L2 = getDistance(P( 2 ),P( 3 ));
01478         double L3 = getDistance(P( 3 ),P( 1 ));
01479         aVal = Max(L1,Max(L2,L3));
01480         break;
01481       }
01482       else if (len == 4){ // quadrangles
01483         double L1 = getDistance(P( 1 ),P( 2 ));
01484         double L2 = getDistance(P( 2 ),P( 3 ));
01485         double L3 = getDistance(P( 3 ),P( 4 ));
01486         double L4 = getDistance(P( 4 ),P( 1 ));
01487         aVal = Max(Max(L1,L2),Max(L3,L4));
01488         break;
01489       }
01490       if (len == 6){ // quadratic triangles
01491         double L1 = getDistance(P( 1 ),P( 2 )) + getDistance(P( 2 ),P( 3 ));
01492         double L2 = getDistance(P( 3 ),P( 4 )) + getDistance(P( 4 ),P( 5 ));
01493         double L3 = getDistance(P( 5 ),P( 6 )) + getDistance(P( 6 ),P( 1 ));
01494         aVal = Max(L1,Max(L2,L3));
01495         //cout<<"L1="<<L1<<" L2="<<L2<<"L3="<<L3<<" aVal="<<aVal<<endl;
01496         break;
01497       }
01498       else if (len == 8){ // quadratic quadrangles
01499         double L1 = getDistance(P( 1 ),P( 2 )) + getDistance(P( 2 ),P( 3 ));
01500         double L2 = getDistance(P( 3 ),P( 4 )) + getDistance(P( 4 ),P( 5 ));
01501         double L3 = getDistance(P( 5 ),P( 6 )) + getDistance(P( 6 ),P( 7 ));
01502         double L4 = getDistance(P( 7 ),P( 8 )) + getDistance(P( 8 ),P( 1 ));
01503         aVal = Max(Max(L1,L2),Max(L3,L4));
01504         break;
01505       }
01506     case SMDSAbs_Volume:
01507       if (len == 4){ // tetraidrs
01508         double L1 = getDistance(P( 1 ),P( 2 ));
01509         double L2 = getDistance(P( 2 ),P( 3 ));
01510         double L3 = getDistance(P( 3 ),P( 1 ));
01511         double L4 = getDistance(P( 1 ),P( 4 ));
01512         double L5 = getDistance(P( 2 ),P( 4 ));
01513         double L6 = getDistance(P( 3 ),P( 4 ));
01514         aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6));
01515         break;
01516       }
01517       else if (len == 5){ // piramids
01518         double L1 = getDistance(P( 1 ),P( 2 ));
01519         double L2 = getDistance(P( 2 ),P( 3 ));
01520         double L3 = getDistance(P( 3 ),P( 4 ));
01521         double L4 = getDistance(P( 4 ),P( 1 ));
01522         double L5 = getDistance(P( 1 ),P( 5 ));
01523         double L6 = getDistance(P( 2 ),P( 5 ));
01524         double L7 = getDistance(P( 3 ),P( 5 ));
01525         double L8 = getDistance(P( 4 ),P( 5 ));
01526 
01527         aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6));
01528         aVal = Max(aVal,Max(L7,L8));
01529         break;
01530       }
01531       else if (len == 6){ // pentaidres
01532         double L1 = getDistance(P( 1 ),P( 2 ));
01533         double L2 = getDistance(P( 2 ),P( 3 ));
01534         double L3 = getDistance(P( 3 ),P( 1 ));
01535         double L4 = getDistance(P( 4 ),P( 5 ));
01536         double L5 = getDistance(P( 5 ),P( 6 ));
01537         double L6 = getDistance(P( 6 ),P( 4 ));
01538         double L7 = getDistance(P( 1 ),P( 4 ));
01539         double L8 = getDistance(P( 2 ),P( 5 ));
01540         double L9 = getDistance(P( 3 ),P( 6 ));
01541 
01542         aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6));
01543         aVal = Max(aVal,Max(Max(L7,L8),L9));
01544         break;
01545       }
01546       else if (len == 8){ // hexaider
01547         double L1 = getDistance(P( 1 ),P( 2 ));
01548         double L2 = getDistance(P( 2 ),P( 3 ));
01549         double L3 = getDistance(P( 3 ),P( 4 ));
01550         double L4 = getDistance(P( 4 ),P( 1 ));
01551         double L5 = getDistance(P( 5 ),P( 6 ));
01552         double L6 = getDistance(P( 6 ),P( 7 ));
01553         double L7 = getDistance(P( 7 ),P( 8 ));
01554         double L8 = getDistance(P( 8 ),P( 5 ));
01555         double L9 = getDistance(P( 1 ),P( 5 ));
01556         double L10= getDistance(P( 2 ),P( 6 ));
01557         double L11= getDistance(P( 3 ),P( 7 ));
01558         double L12= getDistance(P( 4 ),P( 8 ));
01559 
01560         aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6));
01561         aVal = Max(aVal,Max(Max(L7,L8),Max(L9,L10)));
01562         aVal = Max(aVal,Max(L11,L12));
01563         break;
01564 
01565       }
01566 
01567       if (len == 10){ // quadratic tetraidrs
01568         double L1 = getDistance(P( 1 ),P( 5 )) + getDistance(P( 5 ),P( 2 ));
01569         double L2 = getDistance(P( 2 ),P( 6 )) + getDistance(P( 6 ),P( 3 ));
01570         double L3 = getDistance(P( 3 ),P( 7 )) + getDistance(P( 7 ),P( 1 ));
01571         double L4 = getDistance(P( 1 ),P( 8 )) + getDistance(P( 8 ),P( 4 ));
01572         double L5 = getDistance(P( 2 ),P( 9 )) + getDistance(P( 9 ),P( 4 ));
01573         double L6 = getDistance(P( 3 ),P( 10 )) + getDistance(P( 10 ),P( 4 ));
01574         aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6));
01575         break;
01576       }
01577       else if (len == 13){ // quadratic piramids
01578         double L1 = getDistance(P( 1 ),P( 6 )) + getDistance(P( 6 ),P( 2 ));
01579         double L2 = getDistance(P( 2 ),P( 7 )) + getDistance(P( 7 ),P( 3 ));
01580         double L3 = getDistance(P( 3 ),P( 8 )) + getDistance(P( 8 ),P( 4 ));
01581         double L4 = getDistance(P( 4 ),P( 9 )) + getDistance(P( 9 ),P( 1 ));
01582         double L5 = getDistance(P( 1 ),P( 10 )) + getDistance(P( 10 ),P( 5 ));
01583         double L6 = getDistance(P( 2 ),P( 11 )) + getDistance(P( 11 ),P( 5 ));
01584         double L7 = getDistance(P( 3 ),P( 12 )) + getDistance(P( 12 ),P( 5 ));
01585         double L8 = getDistance(P( 4 ),P( 13 )) + getDistance(P( 13 ),P( 5 ));
01586         aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6));
01587         aVal = Max(aVal,Max(L7,L8));
01588         break;
01589       }
01590       else if (len == 15){ // quadratic pentaidres
01591         double L1 = getDistance(P( 1 ),P( 7 )) + getDistance(P( 7 ),P( 2 ));
01592         double L2 = getDistance(P( 2 ),P( 8 )) + getDistance(P( 8 ),P( 3 ));
01593         double L3 = getDistance(P( 3 ),P( 9 )) + getDistance(P( 9 ),P( 1 ));
01594         double L4 = getDistance(P( 4 ),P( 10 )) + getDistance(P( 10 ),P( 5 ));
01595         double L5 = getDistance(P( 5 ),P( 11 )) + getDistance(P( 11 ),P( 6 ));
01596         double L6 = getDistance(P( 6 ),P( 12 )) + getDistance(P( 12 ),P( 4 ));
01597         double L7 = getDistance(P( 1 ),P( 13 )) + getDistance(P( 13 ),P( 4 ));
01598         double L8 = getDistance(P( 2 ),P( 14 )) + getDistance(P( 14 ),P( 5 ));
01599         double L9 = getDistance(P( 3 ),P( 15 )) + getDistance(P( 15 ),P( 6 ));
01600         aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6));
01601         aVal = Max(aVal,Max(Max(L7,L8),L9));
01602         break;
01603       }
01604       else if (len == 20){ // quadratic hexaider
01605         double L1 = getDistance(P( 1 ),P( 9 )) + getDistance(P( 9 ),P( 2 ));
01606         double L2 = getDistance(P( 2 ),P( 10 )) + getDistance(P( 10 ),P( 3 ));
01607         double L3 = getDistance(P( 3 ),P( 11 )) + getDistance(P( 11 ),P( 4 ));
01608         double L4 = getDistance(P( 4 ),P( 12 )) + getDistance(P( 12 ),P( 1 ));
01609         double L5 = getDistance(P( 5 ),P( 13 )) + getDistance(P( 13 ),P( 6 ));
01610         double L6 = getDistance(P( 6 ),P( 14 )) + getDistance(P( 14 ),P( 7 ));
01611         double L7 = getDistance(P( 7 ),P( 15 )) + getDistance(P( 15 ),P( 8 ));
01612         double L8 = getDistance(P( 8 ),P( 16 )) + getDistance(P( 16 ),P( 5 ));
01613         double L9 = getDistance(P( 1 ),P( 17 )) + getDistance(P( 17 ),P( 5 ));
01614         double L10= getDistance(P( 2 ),P( 18 )) + getDistance(P( 18 ),P( 6 ));
01615         double L11= getDistance(P( 3 ),P( 19 )) + getDistance(P( 19 ),P( 7 ));
01616         double L12= getDistance(P( 4 ),P( 20 )) + getDistance(P( 20 ),P( 8 ));
01617         aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(L5,L6));
01618         aVal = Max(aVal,Max(Max(L7,L8),Max(L9,L10)));
01619         aVal = Max(aVal,Max(L11,L12));
01620         break;
01621 
01622       }
01623 
01624     default: aVal=-1;
01625     }
01626 
01627     if (aVal <0){
01628       return 0.;
01629     }
01630 
01631     if ( myPrecision >= 0 )
01632     {
01633       double prec = pow( 10., (double)( myPrecision ) );
01634       aVal = floor( aVal * prec + 0.5 ) / prec;
01635     }
01636 
01637     return aVal;
01638 
01639   }
01640   return 0.;
01641 }
01642 
01643 double Length2D::GetBadRate( double Value, int /*nbNodes*/ ) const
01644 {
01645   // meaningless as it is not quality control functor
01646   return Value;
01647 }
01648 
01649 SMDSAbs_ElementType Length2D::GetType() const
01650 {
01651   return SMDSAbs_Face;
01652 }
01653 
01654 Length2D::Value::Value(double theLength,long thePntId1, long thePntId2):
01655   myLength(theLength)
01656 {
01657   myPntId[0] = thePntId1;  myPntId[1] = thePntId2;
01658   if(thePntId1 > thePntId2){
01659     myPntId[1] = thePntId1;  myPntId[0] = thePntId2;
01660   }
01661 }
01662 
01663 bool Length2D::Value::operator<(const Length2D::Value& x) const{
01664   if(myPntId[0] < x.myPntId[0]) return true;
01665   if(myPntId[0] == x.myPntId[0])
01666     if(myPntId[1] < x.myPntId[1]) return true;
01667   return false;
01668 }
01669 
01670 void Length2D::GetValues(TValues& theValues){
01671   TValues aValues;
01672   SMDS_FaceIteratorPtr anIter = myMesh->facesIterator();
01673   for(; anIter->more(); ){
01674     const SMDS_MeshFace* anElem = anIter->next();
01675 
01676     if(anElem->IsQuadratic()) {
01677       const SMDS_VtkFace* F =
01678         dynamic_cast<const SMDS_VtkFace*>(anElem);
01679       // use special nodes iterator
01680       SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
01681       long aNodeId[4];
01682       gp_Pnt P[4];
01683 
01684       double aLength;
01685       const SMDS_MeshElement* aNode;
01686       if(anIter->more()){
01687         aNode = anIter->next();
01688         const SMDS_MeshNode* aNodes = (SMDS_MeshNode*) aNode;
01689         P[0] = P[1] = gp_Pnt(aNodes->X(),aNodes->Y(),aNodes->Z());
01690         aNodeId[0] = aNodeId[1] = aNode->GetID();
01691         aLength = 0;
01692       }
01693       for(; anIter->more(); ){
01694         const SMDS_MeshNode* N1 = static_cast<const SMDS_MeshNode*> (anIter->next());
01695         P[2] = gp_Pnt(N1->X(),N1->Y(),N1->Z());
01696         aNodeId[2] = N1->GetID();
01697         aLength = P[1].Distance(P[2]);
01698         if(!anIter->more()) break;
01699         const SMDS_MeshNode* N2 = static_cast<const SMDS_MeshNode*> (anIter->next());
01700         P[3] = gp_Pnt(N2->X(),N2->Y(),N2->Z());
01701         aNodeId[3] = N2->GetID();
01702         aLength += P[2].Distance(P[3]);
01703         Value aValue1(aLength,aNodeId[1],aNodeId[2]);
01704         Value aValue2(aLength,aNodeId[2],aNodeId[3]);
01705         P[1] = P[3];
01706         aNodeId[1] = aNodeId[3];
01707         theValues.insert(aValue1);
01708         theValues.insert(aValue2);
01709       }
01710       aLength += P[2].Distance(P[0]);
01711       Value aValue1(aLength,aNodeId[1],aNodeId[2]);
01712       Value aValue2(aLength,aNodeId[2],aNodeId[0]);
01713       theValues.insert(aValue1);
01714       theValues.insert(aValue2);
01715     }
01716     else {
01717       SMDS_ElemIteratorPtr aNodesIter = anElem->nodesIterator();
01718       long aNodeId[2];
01719       gp_Pnt P[3];
01720 
01721       double aLength;
01722       const SMDS_MeshElement* aNode;
01723       if(aNodesIter->more()){
01724         aNode = aNodesIter->next();
01725         const SMDS_MeshNode* aNodes = (SMDS_MeshNode*) aNode;
01726         P[0] = P[1] = gp_Pnt(aNodes->X(),aNodes->Y(),aNodes->Z());
01727         aNodeId[0] = aNodeId[1] = aNode->GetID();
01728         aLength = 0;
01729       }
01730       for(; aNodesIter->more(); ){
01731         aNode = aNodesIter->next();
01732         const SMDS_MeshNode* aNodes = (SMDS_MeshNode*) aNode;
01733         long anId = aNode->GetID();
01734         
01735         P[2] = gp_Pnt(aNodes->X(),aNodes->Y(),aNodes->Z());
01736         
01737         aLength = P[1].Distance(P[2]);
01738         
01739         Value aValue(aLength,aNodeId[1],anId);
01740         aNodeId[1] = anId;
01741         P[1] = P[2];
01742         theValues.insert(aValue);
01743       }
01744 
01745       aLength = P[0].Distance(P[1]);
01746 
01747       Value aValue(aLength,aNodeId[0],aNodeId[1]);
01748       theValues.insert(aValue);
01749     }
01750   }
01751 }
01752 
01753 /*
01754   Class       : MultiConnection
01755   Description : Functor for calculating number of faces conneted to the edge
01756 */
01757 double MultiConnection::GetValue( const TSequenceOfXYZ& P )
01758 {
01759   return 0;
01760 }
01761 double MultiConnection::GetValue( long theId )
01762 {
01763   return getNbMultiConnection( myMesh, theId );
01764 }
01765 
01766 double MultiConnection::GetBadRate( double Value, int /*nbNodes*/ ) const
01767 {
01768   // meaningless as it is not quality control functor
01769   return Value;
01770 }
01771 
01772 SMDSAbs_ElementType MultiConnection::GetType() const
01773 {
01774   return SMDSAbs_Edge;
01775 }
01776 
01777 /*
01778   Class       : MultiConnection2D
01779   Description : Functor for calculating number of faces conneted to the edge
01780 */
01781 double MultiConnection2D::GetValue( const TSequenceOfXYZ& P )
01782 {
01783   return 0;
01784 }
01785 
01786 double MultiConnection2D::GetValue( long theElementId )
01787 {
01788   int aResult = 0;
01789 
01790   const SMDS_MeshElement* aFaceElem = myMesh->FindElement(theElementId);
01791   SMDSAbs_ElementType aType = aFaceElem->GetType();
01792 
01793   switch (aType) {
01794   case SMDSAbs_Face:
01795     {
01796       int i = 0, len = aFaceElem->NbNodes();
01797       SMDS_ElemIteratorPtr anIter = aFaceElem->nodesIterator();
01798       if (!anIter) break;
01799 
01800       const SMDS_MeshNode *aNode, *aNode0;
01801       TColStd_MapOfInteger aMap, aMapPrev;
01802 
01803       for (i = 0; i <= len; i++) {
01804         aMapPrev = aMap;
01805         aMap.Clear();
01806 
01807         int aNb = 0;
01808         if (anIter->more()) {
01809           aNode = (SMDS_MeshNode*)anIter->next();
01810         } else {
01811           if (i == len)
01812             aNode = aNode0;
01813           else
01814             break;
01815         }
01816         if (!aNode) break;
01817         if (i == 0) aNode0 = aNode;
01818 
01819         SMDS_ElemIteratorPtr anElemIter = aNode->GetInverseElementIterator();
01820         while (anElemIter->more()) {
01821           const SMDS_MeshElement* anElem = anElemIter->next();
01822           if (anElem != 0 && anElem->GetType() == SMDSAbs_Face) {
01823             int anId = anElem->GetID();
01824 
01825             aMap.Add(anId);
01826             if (aMapPrev.Contains(anId)) {
01827               aNb++;
01828             }
01829           }
01830         }
01831         aResult = Max(aResult, aNb);
01832       }
01833     }
01834     break;
01835   default:
01836     aResult = 0;
01837   }
01838 
01839   return aResult;
01840 }
01841 
01842 double MultiConnection2D::GetBadRate( double Value, int /*nbNodes*/ ) const
01843 {
01844   // meaningless as it is not quality control functor
01845   return Value;
01846 }
01847 
01848 SMDSAbs_ElementType MultiConnection2D::GetType() const
01849 {
01850   return SMDSAbs_Face;
01851 }
01852 
01853 MultiConnection2D::Value::Value(long thePntId1, long thePntId2)
01854 {
01855   myPntId[0] = thePntId1;  myPntId[1] = thePntId2;
01856   if(thePntId1 > thePntId2){
01857     myPntId[1] = thePntId1;  myPntId[0] = thePntId2;
01858   }
01859 }
01860 
01861 bool MultiConnection2D::Value::operator<(const MultiConnection2D::Value& x) const{
01862   if(myPntId[0] < x.myPntId[0]) return true;
01863   if(myPntId[0] == x.myPntId[0])
01864     if(myPntId[1] < x.myPntId[1]) return true;
01865   return false;
01866 }
01867 
01868 void MultiConnection2D::GetValues(MValues& theValues){
01869   SMDS_FaceIteratorPtr anIter = myMesh->facesIterator();
01870   for(; anIter->more(); ){
01871     const SMDS_MeshFace* anElem = anIter->next();
01872     SMDS_ElemIteratorPtr aNodesIter;
01873     if ( anElem->IsQuadratic() )
01874       aNodesIter = dynamic_cast<const SMDS_VtkFace*>
01875         (anElem)->interlacedNodesElemIterator();
01876     else
01877       aNodesIter = anElem->nodesIterator();
01878     long aNodeId[3];
01879 
01880     //int aNbConnects=0;
01881     const SMDS_MeshNode* aNode0;
01882     const SMDS_MeshNode* aNode1;
01883     const SMDS_MeshNode* aNode2;
01884     if(aNodesIter->more()){
01885       aNode0 = (SMDS_MeshNode*) aNodesIter->next();
01886       aNode1 = aNode0;
01887       const SMDS_MeshNode* aNodes = (SMDS_MeshNode*) aNode1;
01888       aNodeId[0] = aNodeId[1] = aNodes->GetID();
01889     }
01890     for(; aNodesIter->more(); ) {
01891       aNode2 = (SMDS_MeshNode*) aNodesIter->next();
01892       long anId = aNode2->GetID();
01893       aNodeId[2] = anId;
01894 
01895       Value aValue(aNodeId[1],aNodeId[2]);
01896       MValues::iterator aItr = theValues.find(aValue);
01897       if (aItr != theValues.end()){
01898         aItr->second += 1;
01899         //aNbConnects = nb;
01900       }
01901       else {
01902         theValues[aValue] = 1;
01903         //aNbConnects = 1;
01904       }
01905       //cout << "NodeIds: "<<aNodeId[1]<<","<<aNodeId[2]<<" nbconn="<<aNbConnects<<endl;
01906       aNodeId[1] = aNodeId[2];
01907       aNode1 = aNode2;
01908     }
01909     Value aValue(aNodeId[0],aNodeId[2]);
01910     MValues::iterator aItr = theValues.find(aValue);
01911     if (aItr != theValues.end()) {
01912       aItr->second += 1;
01913       //aNbConnects = nb;
01914     }
01915     else {
01916       theValues[aValue] = 1;
01917       //aNbConnects = 1;
01918     }
01919     //cout << "NodeIds: "<<aNodeId[0]<<","<<aNodeId[2]<<" nbconn="<<aNbConnects<<endl;
01920   }
01921 
01922 }
01923 
01924 /*
01925                             PREDICATES
01926 */
01927 
01928 /*
01929   Class       : BadOrientedVolume
01930   Description : Predicate bad oriented volumes
01931 */
01932 
01933 BadOrientedVolume::BadOrientedVolume()
01934 {
01935   myMesh = 0;
01936 }
01937 
01938 void BadOrientedVolume::SetMesh( const SMDS_Mesh* theMesh )
01939 {
01940   myMesh = theMesh;
01941 }
01942 
01943 bool BadOrientedVolume::IsSatisfy( long theId )
01944 {
01945   if ( myMesh == 0 )
01946     return false;
01947 
01948   SMDS_VolumeTool vTool( myMesh->FindElement( theId ));
01949   return !vTool.IsForward();
01950 }
01951 
01952 SMDSAbs_ElementType BadOrientedVolume::GetType() const
01953 {
01954   return SMDSAbs_Volume;
01955 }
01956 
01957 /*
01958   Class       : BareBorderVolume
01959 */
01960 
01961 bool BareBorderVolume::IsSatisfy(long theElementId )
01962 {
01963   SMDS_VolumeTool  myTool;
01964   if ( myTool.Set( myMesh->FindElement(theElementId)))
01965   {
01966     for ( int iF = 0; iF < myTool.NbFaces(); ++iF )
01967       if ( myTool.IsFreeFace( iF ))
01968       {
01969         const SMDS_MeshNode** n = myTool.GetFaceNodes(iF);
01970         vector< const SMDS_MeshNode*> nodes( n, n+myTool.NbFaceNodes(iF));
01971         if ( !myMesh->FindElement( nodes, SMDSAbs_Face, /*Nomedium=*/false))
01972           return true;
01973       }
01974   }
01975   return false;
01976 }
01977 
01978 /*
01979   Class       : BareBorderFace
01980 */
01981 
01982 bool BareBorderFace::IsSatisfy(long theElementId )
01983 {
01984   bool ok = false;
01985   if ( const SMDS_MeshElement* face = myMesh->FindElement(theElementId))
01986   {
01987     if ( face->GetType() == SMDSAbs_Face )
01988     {
01989       int nbN = face->NbCornerNodes();
01990       for ( int i = 0; i < nbN && !ok; ++i )
01991       {
01992         // check if a link is shared by another face
01993         const SMDS_MeshNode* n1 = face->GetNode( i );
01994         const SMDS_MeshNode* n2 = face->GetNode( (i+1)%nbN );
01995         SMDS_ElemIteratorPtr fIt = n1->GetInverseElementIterator( SMDSAbs_Face );
01996         bool isShared = false;
01997         while ( !isShared && fIt->more() )
01998         {
01999           const SMDS_MeshElement* f = fIt->next();
02000           isShared = ( f != face && f->GetNodeIndex(n2) != -1 );
02001         }
02002         if ( !isShared )
02003         {
02004           myLinkNodes.resize( 2 + face->IsQuadratic());
02005           myLinkNodes[0] = n1;
02006           myLinkNodes[1] = n2;
02007           if ( face->IsQuadratic() )
02008             myLinkNodes[2] = face->GetNode( i+nbN );
02009           ok = !myMesh->FindElement( myLinkNodes, SMDSAbs_Edge, /*noMedium=*/false);
02010         }
02011       }
02012     }
02013   }
02014   return ok;
02015 }
02016 
02017 /*
02018   Class       : OverConstrainedVolume
02019 */
02020 
02021 bool OverConstrainedVolume::IsSatisfy(long theElementId )
02022 {
02023   // An element is over-constrained if it has N-1 free borders where
02024   // N is the number of edges/faces for a 2D/3D element.
02025   SMDS_VolumeTool  myTool;
02026   if ( myTool.Set( myMesh->FindElement(theElementId)))
02027   {
02028     int nbSharedFaces = 0;
02029     for ( int iF = 0; iF < myTool.NbFaces(); ++iF )
02030       if ( !myTool.IsFreeFace( iF ) && ++nbSharedFaces > 1 )
02031         break;
02032     return ( nbSharedFaces == 1 );
02033   }
02034   return false;
02035 }
02036 
02037 /*
02038   Class       : OverConstrainedFace
02039 */
02040 
02041 bool OverConstrainedFace::IsSatisfy(long theElementId )
02042 {
02043   // An element is over-constrained if it has N-1 free borders where
02044   // N is the number of edges/faces for a 2D/3D element.
02045   if ( const SMDS_MeshElement* face = myMesh->FindElement(theElementId))
02046     if ( face->GetType() == SMDSAbs_Face )
02047     {
02048       int nbSharedBorders = 0;
02049       int nbN = face->NbCornerNodes();
02050       for ( int i = 0; i < nbN; ++i )
02051       {
02052         // check if a link is shared by another face
02053         const SMDS_MeshNode* n1 = face->GetNode( i );
02054         const SMDS_MeshNode* n2 = face->GetNode( (i+1)%nbN );
02055         SMDS_ElemIteratorPtr fIt = n1->GetInverseElementIterator( SMDSAbs_Face );
02056         bool isShared = false;
02057         while ( !isShared && fIt->more() )
02058         {
02059           const SMDS_MeshElement* f = fIt->next();
02060           isShared = ( f != face && f->GetNodeIndex(n2) != -1 );
02061         }
02062         if ( isShared && ++nbSharedBorders > 1 )
02063           break;
02064       }
02065       return ( nbSharedBorders == 1 );
02066     }
02067   return false;
02068 }
02069 
02070 /*
02071   Class       : FreeBorders
02072   Description : Predicate for free borders
02073 */
02074 
02075 FreeBorders::FreeBorders()
02076 {
02077   myMesh = 0;
02078 }
02079 
02080 void FreeBorders::SetMesh( const SMDS_Mesh* theMesh )
02081 {
02082   myMesh = theMesh;
02083 }
02084 
02085 bool FreeBorders::IsSatisfy( long theId )
02086 {
02087   return getNbMultiConnection( myMesh, theId ) == 1;
02088 }
02089 
02090 SMDSAbs_ElementType FreeBorders::GetType() const
02091 {
02092   return SMDSAbs_Edge;
02093 }
02094 
02095 
02096 /*
02097   Class       : FreeEdges
02098   Description : Predicate for free Edges
02099 */
02100 FreeEdges::FreeEdges()
02101 {
02102   myMesh = 0;
02103 }
02104 
02105 void FreeEdges::SetMesh( const SMDS_Mesh* theMesh )
02106 {
02107   myMesh = theMesh;
02108 }
02109 
02110 bool FreeEdges::IsFreeEdge( const SMDS_MeshNode** theNodes, const int theFaceId  )
02111 {
02112   TColStd_MapOfInteger aMap;
02113   for ( int i = 0; i < 2; i++ )
02114   {
02115     SMDS_ElemIteratorPtr anElemIter = theNodes[ i ]->GetInverseElementIterator();
02116     while( anElemIter->more() )
02117     {
02118       const SMDS_MeshElement* anElem = anElemIter->next();
02119       if ( anElem != 0 && anElem->GetType() == SMDSAbs_Face )
02120       {
02121         int anId = anElem->GetID();
02122 
02123         if ( i == 0 )
02124           aMap.Add( anId );
02125         else if ( aMap.Contains( anId ) && anId != theFaceId )
02126           return false;
02127       }
02128     }
02129   }
02130   return true;
02131 }
02132 
02133 bool FreeEdges::IsSatisfy( long theId )
02134 {
02135   if ( myMesh == 0 )
02136     return false;
02137 
02138   const SMDS_MeshElement* aFace = myMesh->FindElement( theId );
02139   if ( aFace == 0 || aFace->GetType() != SMDSAbs_Face || aFace->NbNodes() < 3 )
02140     return false;
02141 
02142   SMDS_ElemIteratorPtr anIter;
02143   if ( aFace->IsQuadratic() ) {
02144     anIter = dynamic_cast<const SMDS_VtkFace*>
02145       (aFace)->interlacedNodesElemIterator();
02146   }
02147   else {
02148     anIter = aFace->nodesIterator();
02149   }
02150   if ( anIter == 0 )
02151     return false;
02152 
02153   int i = 0, nbNodes = aFace->NbNodes();
02154   std::vector <const SMDS_MeshNode*> aNodes( nbNodes+1 );
02155   while( anIter->more() )
02156   {
02157     const SMDS_MeshNode* aNode = (SMDS_MeshNode*)anIter->next();
02158     if ( aNode == 0 )
02159       return false;
02160     aNodes[ i++ ] = aNode;
02161   }
02162   aNodes[ nbNodes ] = aNodes[ 0 ];
02163 
02164   for ( i = 0; i < nbNodes; i++ )
02165     if ( IsFreeEdge( &aNodes[ i ], theId ) )
02166       return true;
02167 
02168   return false;
02169 }
02170 
02171 SMDSAbs_ElementType FreeEdges::GetType() const
02172 {
02173   return SMDSAbs_Face;
02174 }
02175 
02176 FreeEdges::Border::Border(long theElemId, long thePntId1, long thePntId2):
02177   myElemId(theElemId)
02178 {
02179   myPntId[0] = thePntId1;  myPntId[1] = thePntId2;
02180   if(thePntId1 > thePntId2){
02181     myPntId[1] = thePntId1;  myPntId[0] = thePntId2;
02182   }
02183 }
02184 
02185 bool FreeEdges::Border::operator<(const FreeEdges::Border& x) const{
02186   if(myPntId[0] < x.myPntId[0]) return true;
02187   if(myPntId[0] == x.myPntId[0])
02188     if(myPntId[1] < x.myPntId[1]) return true;
02189   return false;
02190 }
02191 
02192 inline void UpdateBorders(const FreeEdges::Border& theBorder,
02193                           FreeEdges::TBorders& theRegistry,
02194                           FreeEdges::TBorders& theContainer)
02195 {
02196   if(theRegistry.find(theBorder) == theRegistry.end()){
02197     theRegistry.insert(theBorder);
02198     theContainer.insert(theBorder);
02199   }else{
02200     theContainer.erase(theBorder);
02201   }
02202 }
02203 
02204 void FreeEdges::GetBoreders(TBorders& theBorders)
02205 {
02206   TBorders aRegistry;
02207   SMDS_FaceIteratorPtr anIter = myMesh->facesIterator();
02208   for(; anIter->more(); ){
02209     const SMDS_MeshFace* anElem = anIter->next();
02210     long anElemId = anElem->GetID();
02211     SMDS_ElemIteratorPtr aNodesIter;
02212     if ( anElem->IsQuadratic() )
02213       aNodesIter = static_cast<const SMDS_VtkFace*>(anElem)->
02214         interlacedNodesElemIterator();
02215     else
02216       aNodesIter = anElem->nodesIterator();
02217     long aNodeId[2];
02218     const SMDS_MeshElement* aNode;
02219     if(aNodesIter->more()){
02220       aNode = aNodesIter->next();
02221       aNodeId[0] = aNodeId[1] = aNode->GetID();
02222     }
02223     for(; aNodesIter->more(); ){
02224       aNode = aNodesIter->next();
02225       long anId = aNode->GetID();
02226       Border aBorder(anElemId,aNodeId[1],anId);
02227       aNodeId[1] = anId;
02228       //std::cout<<aBorder.myPntId[0]<<"; "<<aBorder.myPntId[1]<<"; "<<aBorder.myElemId<<endl;
02229       UpdateBorders(aBorder,aRegistry,theBorders);
02230     }
02231     Border aBorder(anElemId,aNodeId[0],aNodeId[1]);
02232     //std::cout<<aBorder.myPntId[0]<<"; "<<aBorder.myPntId[1]<<"; "<<aBorder.myElemId<<endl;
02233     UpdateBorders(aBorder,aRegistry,theBorders);
02234   }
02235   //std::cout<<"theBorders.size() = "<<theBorders.size()<<endl;
02236 }
02237 
02238 
02239 /*
02240   Class       : FreeNodes
02241   Description : Predicate for free nodes
02242 */
02243 
02244 FreeNodes::FreeNodes()
02245 {
02246   myMesh = 0;
02247 }
02248 
02249 void FreeNodes::SetMesh( const SMDS_Mesh* theMesh )
02250 {
02251   myMesh = theMesh;
02252 }
02253 
02254 bool FreeNodes::IsSatisfy( long theNodeId )
02255 {
02256   const SMDS_MeshNode* aNode = myMesh->FindNode( theNodeId );
02257   if (!aNode)
02258     return false;
02259 
02260   return (aNode->NbInverseElements() < 1);
02261 }
02262 
02263 SMDSAbs_ElementType FreeNodes::GetType() const
02264 {
02265   return SMDSAbs_Node;
02266 }
02267 
02268 
02269 /*
02270   Class       : FreeFaces
02271   Description : Predicate for free faces
02272 */
02273 
02274 FreeFaces::FreeFaces()
02275 {
02276   myMesh = 0;
02277 }
02278 
02279 void FreeFaces::SetMesh( const SMDS_Mesh* theMesh )
02280 {
02281   myMesh = theMesh;
02282 }
02283 
02284 bool FreeFaces::IsSatisfy( long theId )
02285 {
02286   if (!myMesh) return false;
02287   // check that faces nodes refers to less than two common volumes
02288   const SMDS_MeshElement* aFace = myMesh->FindElement( theId );
02289   if ( !aFace || aFace->GetType() != SMDSAbs_Face )
02290     return false;
02291 
02292   int nbNode = aFace->NbNodes();
02293 
02294   // collect volumes check that number of volumss with count equal nbNode not less than 2
02295   typedef map< SMDS_MeshElement*, int > TMapOfVolume; // map of volume counters
02296   typedef map< SMDS_MeshElement*, int >::iterator TItrMapOfVolume; // iterator
02297   TMapOfVolume mapOfVol;
02298 
02299   SMDS_ElemIteratorPtr nodeItr = aFace->nodesIterator();
02300   while ( nodeItr->more() ) {
02301     const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>(nodeItr->next());
02302     if ( !aNode ) continue;
02303     SMDS_ElemIteratorPtr volItr = aNode->GetInverseElementIterator(SMDSAbs_Volume);
02304     while ( volItr->more() ) {
02305       SMDS_MeshElement* aVol = (SMDS_MeshElement*)volItr->next();
02306       TItrMapOfVolume itr = mapOfVol.insert(make_pair(aVol, 0)).first;
02307       (*itr).second++;
02308     } 
02309   }
02310   int nbVol = 0;
02311   TItrMapOfVolume volItr = mapOfVol.begin();
02312   TItrMapOfVolume volEnd = mapOfVol.end();
02313   for ( ; volItr != volEnd; ++volItr )
02314     if ( (*volItr).second >= nbNode )
02315        nbVol++;
02316   // face is not free if number of volumes constructed on thier nodes more than one
02317   return (nbVol < 2);
02318 }
02319 
02320 SMDSAbs_ElementType FreeFaces::GetType() const
02321 {
02322   return SMDSAbs_Face;
02323 }
02324 
02325 /*
02326   Class       : LinearOrQuadratic
02327   Description : Predicate to verify whether a mesh element is linear
02328 */
02329 
02330 LinearOrQuadratic::LinearOrQuadratic()
02331 {
02332   myMesh = 0;
02333 }
02334 
02335 void LinearOrQuadratic::SetMesh( const SMDS_Mesh* theMesh )
02336 {
02337   myMesh = theMesh;
02338 }
02339 
02340 bool LinearOrQuadratic::IsSatisfy( long theId )
02341 {
02342   if (!myMesh) return false;
02343   const SMDS_MeshElement* anElem = myMesh->FindElement( theId );
02344   if ( !anElem || (myType != SMDSAbs_All && anElem->GetType() != myType) )
02345     return false;
02346   return (!anElem->IsQuadratic());
02347 }
02348 
02349 void LinearOrQuadratic::SetType( SMDSAbs_ElementType theType )
02350 {
02351   myType = theType;
02352 }
02353 
02354 SMDSAbs_ElementType LinearOrQuadratic::GetType() const
02355 {
02356   return myType;
02357 }
02358 
02359 /*
02360   Class       : GroupColor
02361   Description : Functor for check color of group to whic mesh element belongs to
02362 */
02363 
02364 GroupColor::GroupColor()
02365 {
02366 }
02367 
02368 bool GroupColor::IsSatisfy( long theId )
02369 {
02370   return (myIDs.find( theId ) != myIDs.end());
02371 }
02372 
02373 void GroupColor::SetType( SMDSAbs_ElementType theType )
02374 {
02375   myType = theType;
02376 }
02377 
02378 SMDSAbs_ElementType GroupColor::GetType() const
02379 {
02380   return myType;
02381 }
02382 
02383 static bool isEqual( const Quantity_Color& theColor1,
02384                      const Quantity_Color& theColor2 )
02385 {
02386   // tolerance to compare colors
02387   const double tol = 5*1e-3;
02388   return ( fabs( theColor1.Red() - theColor2.Red() ) < tol &&
02389            fabs( theColor1.Green() - theColor2.Green() ) < tol &&
02390            fabs( theColor1.Blue() - theColor2.Blue() ) < tol );
02391 }
02392 
02393 
02394 void GroupColor::SetMesh( const SMDS_Mesh* theMesh )
02395 {
02396   myIDs.clear();
02397   
02398   const SMESHDS_Mesh* aMesh = dynamic_cast<const SMESHDS_Mesh*>(theMesh);
02399   if ( !aMesh )
02400     return;
02401 
02402   int nbGrp = aMesh->GetNbGroups();
02403   if ( !nbGrp )
02404     return;
02405   
02406   // iterates on groups and find necessary elements ids
02407   const std::set<SMESHDS_GroupBase*>& aGroups = aMesh->GetGroups();
02408   set<SMESHDS_GroupBase*>::const_iterator GrIt = aGroups.begin();
02409   for (; GrIt != aGroups.end(); GrIt++) {
02410     SMESHDS_GroupBase* aGrp = (*GrIt);
02411     if ( !aGrp )
02412       continue;
02413     // check type and color of group
02414     if ( !isEqual( myColor, aGrp->GetColor() ) )
02415       continue;
02416     if ( myType != SMDSAbs_All && myType != (SMDSAbs_ElementType)aGrp->GetType() )
02417       continue;
02418 
02419     SMDSAbs_ElementType aGrpElType = (SMDSAbs_ElementType)aGrp->GetType();
02420     if ( myType == aGrpElType || (myType == SMDSAbs_All && aGrpElType != SMDSAbs_Node) ) {
02421       // add elements IDS into control
02422       int aSize = aGrp->Extent();
02423       for (int i = 0; i < aSize; i++)
02424         myIDs.insert( aGrp->GetID(i+1) );
02425     }
02426   }
02427 }
02428 
02429 void GroupColor::SetColorStr( const TCollection_AsciiString& theStr )
02430 {
02431   TCollection_AsciiString aStr = theStr;
02432   aStr.RemoveAll( ' ' );
02433   aStr.RemoveAll( '\t' );
02434   for ( int aPos = aStr.Search( ";;" ); aPos != -1; aPos = aStr.Search( ";;" ) )
02435     aStr.Remove( aPos, 2 );
02436   Standard_Real clr[3];
02437   clr[0] = clr[1] = clr[2] = 0.;
02438   for ( int i = 0; i < 3; i++ ) {
02439     TCollection_AsciiString tmpStr = aStr.Token( ";", i+1 );
02440     if ( !tmpStr.IsEmpty() && tmpStr.IsRealValue() )
02441       clr[i] = tmpStr.RealValue();
02442   }
02443   myColor = Quantity_Color( clr[0], clr[1], clr[2], Quantity_TOC_RGB );
02444 }
02445 
02446 //=======================================================================
02447 // name    : GetRangeStr
02448 // Purpose : Get range as a string.
02449 //           Example: "1,2,3,50-60,63,67,70-"
02450 //=======================================================================
02451 void GroupColor::GetColorStr( TCollection_AsciiString& theResStr ) const
02452 {
02453   theResStr.Clear();
02454   theResStr += TCollection_AsciiString( myColor.Red() );
02455   theResStr += TCollection_AsciiString( ";" ) + TCollection_AsciiString( myColor.Green() );
02456   theResStr += TCollection_AsciiString( ";" ) + TCollection_AsciiString( myColor.Blue() );
02457 }
02458 
02459 /*
02460   Class       : ElemGeomType
02461   Description : Predicate to check element geometry type
02462 */
02463 
02464 ElemGeomType::ElemGeomType()
02465 {
02466   myMesh = 0;
02467   myType = SMDSAbs_All;
02468   myGeomType = SMDSGeom_TRIANGLE;
02469 }
02470 
02471 void ElemGeomType::SetMesh( const SMDS_Mesh* theMesh )
02472 {
02473   myMesh = theMesh;
02474 }
02475 
02476 bool ElemGeomType::IsSatisfy( long theId )
02477 {
02478   if (!myMesh) return false;
02479   const SMDS_MeshElement* anElem = myMesh->FindElement( theId );
02480   if ( !anElem )
02481     return false;
02482   const SMDSAbs_ElementType anElemType = anElem->GetType();
02483   if ( myType != SMDSAbs_All && anElemType != myType )
02484     return false;
02485   const int aNbNode = anElem->NbNodes();
02486   bool isOk = false;
02487   switch( anElemType )
02488   {
02489   case SMDSAbs_Node:
02490     isOk = (myGeomType == SMDSGeom_POINT);
02491     break;
02492 
02493   case SMDSAbs_Edge:
02494     isOk = (myGeomType == SMDSGeom_EDGE);
02495     break;
02496 
02497   case SMDSAbs_Face:
02498     if ( myGeomType == SMDSGeom_TRIANGLE )
02499       isOk = (!anElem->IsPoly() && (anElem->IsQuadratic() ? aNbNode == 6 : aNbNode == 3));
02500     else if ( myGeomType == SMDSGeom_QUADRANGLE )
02501       isOk = (!anElem->IsPoly() && (anElem->IsQuadratic() ? aNbNode == 8 : aNbNode == 4));
02502     else if ( myGeomType == SMDSGeom_POLYGON )
02503       isOk = anElem->IsPoly();
02504     break;
02505 
02506   case SMDSAbs_Volume:
02507     if ( myGeomType == SMDSGeom_TETRA )
02508       isOk = (!anElem->IsPoly() && (anElem->IsQuadratic() ? aNbNode == 10 : aNbNode == 4));
02509     else if ( myGeomType == SMDSGeom_PYRAMID )
02510       isOk = (!anElem->IsPoly() && (anElem->IsQuadratic() ? aNbNode == 13 : aNbNode == 5));
02511     else if ( myGeomType == SMDSGeom_PENTA )
02512       isOk = (!anElem->IsPoly() && (anElem->IsQuadratic() ? aNbNode == 15 : aNbNode == 6));
02513     else if ( myGeomType == SMDSGeom_HEXA )
02514       isOk = (!anElem->IsPoly() && (anElem->IsQuadratic() ? aNbNode == 20 : aNbNode == 8));
02515      else if ( myGeomType == SMDSGeom_POLYHEDRA )
02516       isOk = anElem->IsPoly();
02517     break;
02518     default: break;
02519   }
02520   return isOk;
02521 }
02522 
02523 void ElemGeomType::SetType( SMDSAbs_ElementType theType )
02524 {
02525   myType = theType;
02526 }
02527 
02528 SMDSAbs_ElementType ElemGeomType::GetType() const
02529 {
02530   return myType;
02531 }
02532 
02533 void ElemGeomType::SetGeomType( SMDSAbs_GeometryType theType )
02534 {
02535   myGeomType = theType;
02536 }
02537 
02538 SMDSAbs_GeometryType ElemGeomType::GetGeomType() const
02539 {
02540   return myGeomType;
02541 }
02542 
02543 //================================================================================
02547 //================================================================================
02548 
02549 CoplanarFaces::CoplanarFaces()
02550   : myMesh(0), myFaceID(0), myToler(0)
02551 {
02552 }
02553 bool CoplanarFaces::IsSatisfy( long theElementId )
02554 {
02555   if ( myCoplanarIDs.empty() )
02556   {
02557     // Build a set of coplanar face ids
02558 
02559     if ( !myMesh || !myFaceID || !myToler )
02560       return false;
02561 
02562     const SMDS_MeshElement* face = myMesh->FindElement( myFaceID );
02563     if ( !face || face->GetType() != SMDSAbs_Face )
02564       return false;
02565 
02566     bool normOK;
02567     gp_Vec myNorm = getNormale( static_cast<const SMDS_MeshFace*>(face), &normOK );
02568     if (!normOK)
02569       return false;
02570 
02571     const double radianTol = myToler * PI180;
02572     typedef SMDS_StdIterator< const SMDS_MeshElement*, SMDS_ElemIteratorPtr > TFaceIt;
02573     std::set<const SMDS_MeshElement*> checkedFaces, checkedNodes;
02574     std::list<const SMDS_MeshElement*> faceQueue( 1, face );
02575     while ( !faceQueue.empty() )
02576     {
02577       face = faceQueue.front();
02578       if ( checkedFaces.insert( face ).second )
02579       {
02580         gp_Vec norm = getNormale( static_cast<const SMDS_MeshFace*>(face), &normOK );
02581         if (!normOK || myNorm.Angle( norm ) <= radianTol)
02582         {
02583           myCoplanarIDs.insert( face->GetID() );
02584           std::set<const SMDS_MeshElement*> neighborFaces;
02585           for ( int i = 0; i < face->NbCornerNodes(); ++i )
02586           {
02587             const SMDS_MeshNode* n = face->GetNode( i );
02588             if ( checkedNodes.insert( n ).second )
02589               neighborFaces.insert( TFaceIt( n->GetInverseElementIterator(SMDSAbs_Face)),
02590                                     TFaceIt());
02591           }
02592           faceQueue.insert( faceQueue.end(), neighborFaces.begin(), neighborFaces.end() );
02593         }
02594       }
02595       faceQueue.pop_front();
02596     }
02597   }
02598   return myCoplanarIDs.count( theElementId );
02599 }
02600 
02601 /*
02602   *Class       : RangeOfIds
02603   *Description : Predicate for Range of Ids.
02604   *              Range may be specified with two ways.
02605   *              1. Using AddToRange method
02606   *              2. With SetRangeStr method. Parameter of this method is a string
02607   *                 like as "1,2,3,50-60,63,67,70-"
02608 */
02609 
02610 //=======================================================================
02611 // name    : RangeOfIds
02612 // Purpose : Constructor
02613 //=======================================================================
02614 RangeOfIds::RangeOfIds()
02615 {
02616   myMesh = 0;
02617   myType = SMDSAbs_All;
02618 }
02619 
02620 //=======================================================================
02621 // name    : SetMesh
02622 // Purpose : Set mesh
02623 //=======================================================================
02624 void RangeOfIds::SetMesh( const SMDS_Mesh* theMesh )
02625 {
02626   myMesh = theMesh;
02627 }
02628 
02629 //=======================================================================
02630 // name    : AddToRange
02631 // Purpose : Add ID to the range
02632 //=======================================================================
02633 bool RangeOfIds::AddToRange( long theEntityId )
02634 {
02635   myIds.Add( theEntityId );
02636   return true;
02637 }
02638 
02639 //=======================================================================
02640 // name    : GetRangeStr
02641 // Purpose : Get range as a string.
02642 //           Example: "1,2,3,50-60,63,67,70-"
02643 //=======================================================================
02644 void RangeOfIds::GetRangeStr( TCollection_AsciiString& theResStr )
02645 {
02646   theResStr.Clear();
02647 
02648   TColStd_SequenceOfInteger     anIntSeq;
02649   TColStd_SequenceOfAsciiString aStrSeq;
02650 
02651   TColStd_MapIteratorOfMapOfInteger anIter( myIds );
02652   for ( ; anIter.More(); anIter.Next() )
02653   {
02654     int anId = anIter.Key();
02655     TCollection_AsciiString aStr( anId );
02656     anIntSeq.Append( anId );
02657     aStrSeq.Append( aStr );
02658   }
02659 
02660   for ( int i = 1, n = myMin.Length(); i <= n; i++ )
02661   {
02662     int aMinId = myMin( i );
02663     int aMaxId = myMax( i );
02664 
02665     TCollection_AsciiString aStr;
02666     if ( aMinId != IntegerFirst() )
02667       aStr += aMinId;
02668 
02669     aStr += "-";
02670 
02671     if ( aMaxId != IntegerLast() )
02672       aStr += aMaxId;
02673 
02674     // find position of the string in result sequence and insert string in it
02675     if ( anIntSeq.Length() == 0 )
02676     {
02677       anIntSeq.Append( aMinId );
02678       aStrSeq.Append( aStr );
02679     }
02680     else
02681     {
02682       if ( aMinId < anIntSeq.First() )
02683       {
02684         anIntSeq.Prepend( aMinId );
02685         aStrSeq.Prepend( aStr );
02686       }
02687       else if ( aMinId > anIntSeq.Last() )
02688       {
02689         anIntSeq.Append( aMinId );
02690         aStrSeq.Append( aStr );
02691       }
02692       else
02693         for ( int j = 1, k = anIntSeq.Length(); j <= k; j++ )
02694           if ( aMinId < anIntSeq( j ) )
02695           {
02696             anIntSeq.InsertBefore( j, aMinId );
02697             aStrSeq.InsertBefore( j, aStr );
02698             break;
02699           }
02700     }
02701   }
02702 
02703   if ( aStrSeq.Length() == 0 )
02704     return;
02705 
02706   theResStr = aStrSeq( 1 );
02707   for ( int j = 2, k = aStrSeq.Length(); j <= k; j++  )
02708   {
02709     theResStr += ",";
02710     theResStr += aStrSeq( j );
02711   }
02712 }
02713 
02714 //=======================================================================
02715 // name    : SetRangeStr
02716 // Purpose : Define range with string
02717 //           Example of entry string: "1,2,3,50-60,63,67,70-"
02718 //=======================================================================
02719 bool RangeOfIds::SetRangeStr( const TCollection_AsciiString& theStr )
02720 {
02721   myMin.Clear();
02722   myMax.Clear();
02723   myIds.Clear();
02724 
02725   TCollection_AsciiString aStr = theStr;
02726   aStr.RemoveAll( ' ' );
02727   aStr.RemoveAll( '\t' );
02728 
02729   for ( int aPos = aStr.Search( ",," ); aPos != -1; aPos = aStr.Search( ",," ) )
02730     aStr.Remove( aPos, 2 );
02731 
02732   TCollection_AsciiString tmpStr = aStr.Token( ",", 1 );
02733   int i = 1;
02734   while ( tmpStr != "" )
02735   {
02736     tmpStr = aStr.Token( ",", i++ );
02737     int aPos = tmpStr.Search( '-' );
02738 
02739     if ( aPos == -1 )
02740     {
02741       if ( tmpStr.IsIntegerValue() )
02742         myIds.Add( tmpStr.IntegerValue() );
02743       else
02744         return false;
02745     }
02746     else
02747     {
02748       TCollection_AsciiString aMaxStr = tmpStr.Split( aPos );
02749       TCollection_AsciiString aMinStr = tmpStr;
02750 
02751       while ( aMinStr.Search( "-" ) != -1 ) aMinStr.RemoveAll( '-' );
02752       while ( aMaxStr.Search( "-" ) != -1 ) aMaxStr.RemoveAll( '-' );
02753 
02754       if ( (!aMinStr.IsEmpty() && !aMinStr.IsIntegerValue()) ||
02755            (!aMaxStr.IsEmpty() && !aMaxStr.IsIntegerValue()) )
02756         return false;
02757 
02758       myMin.Append( aMinStr.IsEmpty() ? IntegerFirst() : aMinStr.IntegerValue() );
02759       myMax.Append( aMaxStr.IsEmpty() ? IntegerLast()  : aMaxStr.IntegerValue() );
02760     }
02761   }
02762 
02763   return true;
02764 }
02765 
02766 //=======================================================================
02767 // name    : GetType
02768 // Purpose : Get type of supported entities
02769 //=======================================================================
02770 SMDSAbs_ElementType RangeOfIds::GetType() const
02771 {
02772   return myType;
02773 }
02774 
02775 //=======================================================================
02776 // name    : SetType
02777 // Purpose : Set type of supported entities
02778 //=======================================================================
02779 void RangeOfIds::SetType( SMDSAbs_ElementType theType )
02780 {
02781   myType = theType;
02782 }
02783 
02784 //=======================================================================
02785 // name    : IsSatisfy
02786 // Purpose : Verify whether entity satisfies to this rpedicate
02787 //=======================================================================
02788 bool RangeOfIds::IsSatisfy( long theId )
02789 {
02790   if ( !myMesh )
02791     return false;
02792 
02793   if ( myType == SMDSAbs_Node )
02794   {
02795     if ( myMesh->FindNode( theId ) == 0 )
02796       return false;
02797   }
02798   else
02799   {
02800     const SMDS_MeshElement* anElem = myMesh->FindElement( theId );
02801     if ( anElem == 0 || (myType != anElem->GetType() && myType != SMDSAbs_All ))
02802       return false;
02803   }
02804 
02805   if ( myIds.Contains( theId ) )
02806     return true;
02807 
02808   for ( int i = 1, n = myMin.Length(); i <= n; i++ )
02809     if ( theId >= myMin( i ) && theId <= myMax( i ) )
02810       return true;
02811 
02812   return false;
02813 }
02814 
02815 /*
02816   Class       : Comparator
02817   Description : Base class for comparators
02818 */
02819 Comparator::Comparator():
02820   myMargin(0)
02821 {}
02822 
02823 Comparator::~Comparator()
02824 {}
02825 
02826 void Comparator::SetMesh( const SMDS_Mesh* theMesh )
02827 {
02828   if ( myFunctor )
02829     myFunctor->SetMesh( theMesh );
02830 }
02831 
02832 void Comparator::SetMargin( double theValue )
02833 {
02834   myMargin = theValue;
02835 }
02836 
02837 void Comparator::SetNumFunctor( NumericalFunctorPtr theFunct )
02838 {
02839   myFunctor = theFunct;
02840 }
02841 
02842 SMDSAbs_ElementType Comparator::GetType() const
02843 {
02844   return myFunctor ? myFunctor->GetType() : SMDSAbs_All;
02845 }
02846 
02847 double Comparator::GetMargin()
02848 {
02849   return myMargin;
02850 }
02851 
02852 
02853 /*
02854   Class       : LessThan
02855   Description : Comparator "<"
02856 */
02857 bool LessThan::IsSatisfy( long theId )
02858 {
02859   return myFunctor && myFunctor->GetValue( theId ) < myMargin;
02860 }
02861 
02862 
02863 /*
02864   Class       : MoreThan
02865   Description : Comparator ">"
02866 */
02867 bool MoreThan::IsSatisfy( long theId )
02868 {
02869   return myFunctor && myFunctor->GetValue( theId ) > myMargin;
02870 }
02871 
02872 
02873 /*
02874   Class       : EqualTo
02875   Description : Comparator "="
02876 */
02877 EqualTo::EqualTo():
02878   myToler(Precision::Confusion())
02879 {}
02880 
02881 bool EqualTo::IsSatisfy( long theId )
02882 {
02883   return myFunctor && fabs( myFunctor->GetValue( theId ) - myMargin ) < myToler;
02884 }
02885 
02886 void EqualTo::SetTolerance( double theToler )
02887 {
02888   myToler = theToler;
02889 }
02890 
02891 double EqualTo::GetTolerance()
02892 {
02893   return myToler;
02894 }
02895 
02896 /*
02897   Class       : LogicalNOT
02898   Description : Logical NOT predicate
02899 */
02900 LogicalNOT::LogicalNOT()
02901 {}
02902 
02903 LogicalNOT::~LogicalNOT()
02904 {}
02905 
02906 bool LogicalNOT::IsSatisfy( long theId )
02907 {
02908   return myPredicate && !myPredicate->IsSatisfy( theId );
02909 }
02910 
02911 void LogicalNOT::SetMesh( const SMDS_Mesh* theMesh )
02912 {
02913   if ( myPredicate )
02914     myPredicate->SetMesh( theMesh );
02915 }
02916 
02917 void LogicalNOT::SetPredicate( PredicatePtr thePred )
02918 {
02919   myPredicate = thePred;
02920 }
02921 
02922 SMDSAbs_ElementType LogicalNOT::GetType() const
02923 {
02924   return myPredicate ? myPredicate->GetType() : SMDSAbs_All;
02925 }
02926 
02927 
02928 /*
02929   Class       : LogicalBinary
02930   Description : Base class for binary logical predicate
02931 */
02932 LogicalBinary::LogicalBinary()
02933 {}
02934 
02935 LogicalBinary::~LogicalBinary()
02936 {}
02937 
02938 void LogicalBinary::SetMesh( const SMDS_Mesh* theMesh )
02939 {
02940   if ( myPredicate1 )
02941     myPredicate1->SetMesh( theMesh );
02942 
02943   if ( myPredicate2 )
02944     myPredicate2->SetMesh( theMesh );
02945 }
02946 
02947 void LogicalBinary::SetPredicate1( PredicatePtr thePredicate )
02948 {
02949   myPredicate1 = thePredicate;
02950 }
02951 
02952 void LogicalBinary::SetPredicate2( PredicatePtr thePredicate )
02953 {
02954   myPredicate2 = thePredicate;
02955 }
02956 
02957 SMDSAbs_ElementType LogicalBinary::GetType() const
02958 {
02959   if ( !myPredicate1 || !myPredicate2 )
02960     return SMDSAbs_All;
02961 
02962   SMDSAbs_ElementType aType1 = myPredicate1->GetType();
02963   SMDSAbs_ElementType aType2 = myPredicate2->GetType();
02964 
02965   return aType1 == aType2 ? aType1 : SMDSAbs_All;
02966 }
02967 
02968 
02969 /*
02970   Class       : LogicalAND
02971   Description : Logical AND
02972 */
02973 bool LogicalAND::IsSatisfy( long theId )
02974 {
02975   return
02976     myPredicate1 &&
02977     myPredicate2 &&
02978     myPredicate1->IsSatisfy( theId ) &&
02979     myPredicate2->IsSatisfy( theId );
02980 }
02981 
02982 
02983 /*
02984   Class       : LogicalOR
02985   Description : Logical OR
02986 */
02987 bool LogicalOR::IsSatisfy( long theId )
02988 {
02989   return
02990     myPredicate1 &&
02991     myPredicate2 &&
02992     (myPredicate1->IsSatisfy( theId ) ||
02993     myPredicate2->IsSatisfy( theId ));
02994 }
02995 
02996 
02997 /*
02998                               FILTER
02999 */
03000 
03001 Filter::Filter()
03002 {}
03003 
03004 Filter::~Filter()
03005 {}
03006 
03007 void Filter::SetPredicate( PredicatePtr thePredicate )
03008 {
03009   myPredicate = thePredicate;
03010 }
03011 
03012 template<class TElement, class TIterator, class TPredicate>
03013 inline void FillSequence(const TIterator& theIterator,
03014                          TPredicate& thePredicate,
03015                          Filter::TIdSequence& theSequence)
03016 {
03017   if ( theIterator ) {
03018     while( theIterator->more() ) {
03019       TElement anElem = theIterator->next();
03020       long anId = anElem->GetID();
03021       if ( thePredicate->IsSatisfy( anId ) )
03022         theSequence.push_back( anId );
03023     }
03024   }
03025 }
03026 
03027 void
03028 Filter::
03029 GetElementsId( const SMDS_Mesh* theMesh,
03030                PredicatePtr thePredicate,
03031                TIdSequence& theSequence )
03032 {
03033   theSequence.clear();
03034 
03035   if ( !theMesh || !thePredicate )
03036     return;
03037 
03038   thePredicate->SetMesh( theMesh );
03039 
03040   SMDSAbs_ElementType aType = thePredicate->GetType();
03041   switch(aType){
03042   case SMDSAbs_Node:
03043     FillSequence<const SMDS_MeshNode*>(theMesh->nodesIterator(),thePredicate,theSequence);
03044     break;
03045   case SMDSAbs_Edge:
03046     FillSequence<const SMDS_MeshElement*>(theMesh->edgesIterator(),thePredicate,theSequence);
03047     break;
03048   case SMDSAbs_Face:
03049     FillSequence<const SMDS_MeshElement*>(theMesh->facesIterator(),thePredicate,theSequence);
03050     break;
03051   case SMDSAbs_Volume:
03052     FillSequence<const SMDS_MeshElement*>(theMesh->volumesIterator(),thePredicate,theSequence);
03053     break;
03054   case SMDSAbs_All:
03055     FillSequence<const SMDS_MeshElement*>(theMesh->edgesIterator(),thePredicate,theSequence);
03056     FillSequence<const SMDS_MeshElement*>(theMesh->facesIterator(),thePredicate,theSequence);
03057     FillSequence<const SMDS_MeshElement*>(theMesh->volumesIterator(),thePredicate,theSequence);
03058     break;
03059   }
03060 }
03061 
03062 void
03063 Filter::GetElementsId( const SMDS_Mesh* theMesh,
03064                        Filter::TIdSequence& theSequence )
03065 {
03066   GetElementsId(theMesh,myPredicate,theSequence);
03067 }
03068 
03069 /*
03070                               ManifoldPart
03071 */
03072 
03073 typedef std::set<SMDS_MeshFace*>                    TMapOfFacePtr;
03074 
03075 /*
03076    Internal class Link
03077 */
03078 
03079 ManifoldPart::Link::Link( SMDS_MeshNode* theNode1,
03080                           SMDS_MeshNode* theNode2 )
03081 {
03082   myNode1 = theNode1;
03083   myNode2 = theNode2;
03084 }
03085 
03086 ManifoldPart::Link::~Link()
03087 {
03088   myNode1 = 0;
03089   myNode2 = 0;
03090 }
03091 
03092 bool ManifoldPart::Link::IsEqual( const ManifoldPart::Link& theLink ) const
03093 {
03094   if ( myNode1 == theLink.myNode1 &&
03095        myNode2 == theLink.myNode2 )
03096     return true;
03097   else if ( myNode1 == theLink.myNode2 &&
03098             myNode2 == theLink.myNode1 )
03099     return true;
03100   else
03101     return false;
03102 }
03103 
03104 bool ManifoldPart::Link::operator<( const ManifoldPart::Link& x ) const
03105 {
03106   if(myNode1 < x.myNode1) return true;
03107   if(myNode1 == x.myNode1)
03108     if(myNode2 < x.myNode2) return true;
03109   return false;
03110 }
03111 
03112 bool ManifoldPart::IsEqual( const ManifoldPart::Link& theLink1,
03113                             const ManifoldPart::Link& theLink2 )
03114 {
03115   return theLink1.IsEqual( theLink2 );
03116 }
03117 
03118 ManifoldPart::ManifoldPart()
03119 {
03120   myMesh = 0;
03121   myAngToler = Precision::Angular();
03122   myIsOnlyManifold = true;
03123 }
03124 
03125 ManifoldPart::~ManifoldPart()
03126 {
03127   myMesh = 0;
03128 }
03129 
03130 void ManifoldPart::SetMesh( const SMDS_Mesh* theMesh )
03131 {
03132   myMesh = theMesh;
03133   process();
03134 }
03135 
03136 SMDSAbs_ElementType ManifoldPart::GetType() const
03137 { return SMDSAbs_Face; }
03138 
03139 bool ManifoldPart::IsSatisfy( long theElementId )
03140 {
03141   return myMapIds.Contains( theElementId );
03142 }
03143 
03144 void ManifoldPart::SetAngleTolerance( const double theAngToler )
03145 { myAngToler = theAngToler; }
03146 
03147 double ManifoldPart::GetAngleTolerance() const
03148 { return myAngToler; }
03149 
03150 void ManifoldPart::SetIsOnlyManifold( const bool theIsOnly )
03151 { myIsOnlyManifold = theIsOnly; }
03152 
03153 void ManifoldPart::SetStartElem( const long  theStartId )
03154 { myStartElemId = theStartId; }
03155 
03156 bool ManifoldPart::process()
03157 {
03158   myMapIds.Clear();
03159   myMapBadGeomIds.Clear();
03160 
03161   myAllFacePtr.clear();
03162   myAllFacePtrIntDMap.clear();
03163   if ( !myMesh )
03164     return false;
03165 
03166   // collect all faces into own map
03167   SMDS_FaceIteratorPtr anFaceItr = myMesh->facesIterator();
03168   for (; anFaceItr->more(); )
03169   {
03170     SMDS_MeshFace* aFacePtr = (SMDS_MeshFace*)anFaceItr->next();
03171     myAllFacePtr.push_back( aFacePtr );
03172     myAllFacePtrIntDMap[aFacePtr] = myAllFacePtr.size()-1;
03173   }
03174 
03175   SMDS_MeshFace* aStartFace = (SMDS_MeshFace*)myMesh->FindElement( myStartElemId );
03176   if ( !aStartFace )
03177     return false;
03178 
03179   // the map of non manifold links and bad geometry
03180   TMapOfLink aMapOfNonManifold;
03181   TColStd_MapOfInteger aMapOfTreated;
03182 
03183   // begin cycle on faces from start index and run on vector till the end
03184   //  and from begin to start index to cover whole vector
03185   const int aStartIndx = myAllFacePtrIntDMap[aStartFace];
03186   bool isStartTreat = false;
03187   for ( int fi = aStartIndx; !isStartTreat || fi != aStartIndx ; fi++ )
03188   {
03189     if ( fi == aStartIndx )
03190       isStartTreat = true;
03191     // as result next time when fi will be equal to aStartIndx
03192 
03193     SMDS_MeshFace* aFacePtr = myAllFacePtr[ fi ];
03194     if ( aMapOfTreated.Contains( aFacePtr->GetID() ) )
03195       continue;
03196 
03197     aMapOfTreated.Add( aFacePtr->GetID() );
03198     TColStd_MapOfInteger aResFaces;
03199     if ( !findConnected( myAllFacePtrIntDMap, aFacePtr,
03200                          aMapOfNonManifold, aResFaces ) )
03201       continue;
03202     TColStd_MapIteratorOfMapOfInteger anItr( aResFaces );
03203     for ( ; anItr.More(); anItr.Next() )
03204     {
03205       int aFaceId = anItr.Key();
03206       aMapOfTreated.Add( aFaceId );
03207       myMapIds.Add( aFaceId );
03208     }
03209 
03210     if ( fi == ( myAllFacePtr.size() - 1 ) )
03211       fi = 0;
03212   } // end run on vector of faces
03213   return !myMapIds.IsEmpty();
03214 }
03215 
03216 static void getLinks( const SMDS_MeshFace* theFace,
03217                       ManifoldPart::TVectorOfLink& theLinks )
03218 {
03219   int aNbNode = theFace->NbNodes();
03220   SMDS_ElemIteratorPtr aNodeItr = theFace->nodesIterator();
03221   int i = 1;
03222   SMDS_MeshNode* aNode = 0;
03223   for ( ; aNodeItr->more() && i <= aNbNode; )
03224   {
03225 
03226     SMDS_MeshNode* aN1 = (SMDS_MeshNode*)aNodeItr->next();
03227     if ( i == 1 )
03228       aNode = aN1;
03229     i++;
03230     SMDS_MeshNode* aN2 = ( i >= aNbNode ) ? aNode : (SMDS_MeshNode*)aNodeItr->next();
03231     i++;
03232     ManifoldPart::Link aLink( aN1, aN2 );
03233     theLinks.push_back( aLink );
03234   }
03235 }
03236 
03237 bool ManifoldPart::findConnected
03238                  ( const ManifoldPart::TDataMapFacePtrInt& theAllFacePtrInt,
03239                   SMDS_MeshFace*                           theStartFace,
03240                   ManifoldPart::TMapOfLink&                theNonManifold,
03241                   TColStd_MapOfInteger&                    theResFaces )
03242 {
03243   theResFaces.Clear();
03244   if ( !theAllFacePtrInt.size() )
03245     return false;
03246 
03247   if ( getNormale( theStartFace ).SquareModulus() <= gp::Resolution() )
03248   {
03249     myMapBadGeomIds.Add( theStartFace->GetID() );
03250     return false;
03251   }
03252 
03253   ManifoldPart::TMapOfLink aMapOfBoundary, aMapToSkip;
03254   ManifoldPart::TVectorOfLink aSeqOfBoundary;
03255   theResFaces.Add( theStartFace->GetID() );
03256   ManifoldPart::TDataMapOfLinkFacePtr aDMapLinkFace;
03257 
03258   expandBoundary( aMapOfBoundary, aSeqOfBoundary,
03259                  aDMapLinkFace, theNonManifold, theStartFace );
03260 
03261   bool isDone = false;
03262   while ( !isDone && aMapOfBoundary.size() != 0 )
03263   {
03264     bool isToReset = false;
03265     ManifoldPart::TVectorOfLink::iterator pLink = aSeqOfBoundary.begin();
03266     for ( ; !isToReset && pLink != aSeqOfBoundary.end(); ++pLink )
03267     {
03268       ManifoldPart::Link aLink = *pLink;
03269       if ( aMapToSkip.find( aLink ) != aMapToSkip.end() )
03270         continue;
03271       // each link could be treated only once
03272       aMapToSkip.insert( aLink );
03273 
03274       ManifoldPart::TVectorOfFacePtr aFaces;
03275       // find next
03276       if ( myIsOnlyManifold &&
03277            (theNonManifold.find( aLink ) != theNonManifold.end()) )
03278         continue;
03279       else
03280       {
03281         getFacesByLink( aLink, aFaces );
03282         // filter the element to keep only indicated elements
03283         ManifoldPart::TVectorOfFacePtr aFiltered;
03284         ManifoldPart::TVectorOfFacePtr::iterator pFace = aFaces.begin();
03285         for ( ; pFace != aFaces.end(); ++pFace )
03286         {
03287           SMDS_MeshFace* aFace = *pFace;
03288           if ( myAllFacePtrIntDMap.find( aFace ) != myAllFacePtrIntDMap.end() )
03289             aFiltered.push_back( aFace );
03290         }
03291         aFaces = aFiltered;
03292         if ( aFaces.size() < 2 )  // no neihgbour faces
03293           continue;
03294         else if ( myIsOnlyManifold && aFaces.size() > 2 ) // non manifold case
03295         {
03296           theNonManifold.insert( aLink );
03297           continue;
03298         }
03299       }
03300 
03301       // compare normal with normals of neighbor element
03302       SMDS_MeshFace* aPrevFace = aDMapLinkFace[ aLink ];
03303       ManifoldPart::TVectorOfFacePtr::iterator pFace = aFaces.begin();
03304       for ( ; pFace != aFaces.end(); ++pFace )
03305       {
03306         SMDS_MeshFace* aNextFace = *pFace;
03307         if ( aPrevFace == aNextFace )
03308           continue;
03309         int anNextFaceID = aNextFace->GetID();
03310         if ( myIsOnlyManifold && theResFaces.Contains( anNextFaceID ) )
03311          // should not be with non manifold restriction. probably bad topology
03312           continue;
03313         // check if face was treated and skipped
03314         if ( myMapBadGeomIds.Contains( anNextFaceID ) ||
03315              !isInPlane( aPrevFace, aNextFace ) )
03316           continue;
03317         // add new element to connected and extend the boundaries.
03318         theResFaces.Add( anNextFaceID );
03319         expandBoundary( aMapOfBoundary, aSeqOfBoundary,
03320                         aDMapLinkFace, theNonManifold, aNextFace );
03321         isToReset = true;
03322       }
03323     }
03324     isDone = !isToReset;
03325   }
03326 
03327   return !theResFaces.IsEmpty();
03328 }
03329 
03330 bool ManifoldPart::isInPlane( const SMDS_MeshFace* theFace1,
03331                               const SMDS_MeshFace* theFace2 )
03332 {
03333   gp_Dir aNorm1 = gp_Dir( getNormale( theFace1 ) );
03334   gp_XYZ aNorm2XYZ = getNormale( theFace2 );
03335   if ( aNorm2XYZ.SquareModulus() <= gp::Resolution() )
03336   {
03337     myMapBadGeomIds.Add( theFace2->GetID() );
03338     return false;
03339   }
03340   if ( aNorm1.IsParallel( gp_Dir( aNorm2XYZ ), myAngToler ) )
03341     return true;
03342 
03343   return false;
03344 }
03345 
03346 void ManifoldPart::expandBoundary
03347                    ( ManifoldPart::TMapOfLink&            theMapOfBoundary,
03348                      ManifoldPart::TVectorOfLink&         theSeqOfBoundary,
03349                      ManifoldPart::TDataMapOfLinkFacePtr& theDMapLinkFacePtr,
03350                      ManifoldPart::TMapOfLink&            theNonManifold,
03351                      SMDS_MeshFace*                       theNextFace ) const
03352 {
03353   ManifoldPart::TVectorOfLink aLinks;
03354   getLinks( theNextFace, aLinks );
03355   int aNbLink = (int)aLinks.size();
03356   for ( int i = 0; i < aNbLink; i++ )
03357   {
03358     ManifoldPart::Link aLink = aLinks[ i ];
03359     if ( myIsOnlyManifold && (theNonManifold.find( aLink ) != theNonManifold.end()) )
03360       continue;
03361     if ( theMapOfBoundary.find( aLink ) != theMapOfBoundary.end() )
03362     {
03363       if ( myIsOnlyManifold )
03364       {
03365         // remove from boundary
03366         theMapOfBoundary.erase( aLink );
03367         ManifoldPart::TVectorOfLink::iterator pLink = theSeqOfBoundary.begin();
03368         for ( ; pLink != theSeqOfBoundary.end(); ++pLink )
03369         {
03370           ManifoldPart::Link aBoundLink = *pLink;
03371           if ( aBoundLink.IsEqual( aLink ) )
03372           {
03373             theSeqOfBoundary.erase( pLink );
03374             break;
03375           }
03376         }
03377       }
03378     }
03379     else
03380     {
03381       theMapOfBoundary.insert( aLink );
03382       theSeqOfBoundary.push_back( aLink );
03383       theDMapLinkFacePtr[ aLink ] = theNextFace;
03384     }
03385   }
03386 }
03387 
03388 void ManifoldPart::getFacesByLink( const ManifoldPart::Link& theLink,
03389                                    ManifoldPart::TVectorOfFacePtr& theFaces ) const
03390 {
03391   std::set<SMDS_MeshCell *> aSetOfFaces;
03392   // take all faces that shared first node
03393   SMDS_ElemIteratorPtr anItr = theLink.myNode1->facesIterator();
03394   for ( ; anItr->more(); )
03395   {
03396     SMDS_MeshFace* aFace = (SMDS_MeshFace*)anItr->next();
03397     if ( !aFace )
03398       continue;
03399     aSetOfFaces.insert( aFace );
03400   }
03401   // take all faces that shared second node
03402   anItr = theLink.myNode2->facesIterator();
03403   // find the common part of two sets
03404   for ( ; anItr->more(); )
03405   {
03406     SMDS_MeshFace* aFace = (SMDS_MeshFace*)anItr->next();
03407     if ( aSetOfFaces.count( aFace ) )
03408       theFaces.push_back( aFace );
03409   }
03410 }
03411 
03412 
03413 /*
03414    ElementsOnSurface
03415 */
03416 
03417 ElementsOnSurface::ElementsOnSurface()
03418 {
03419   myMesh = 0;
03420   myIds.Clear();
03421   myType = SMDSAbs_All;
03422   mySurf.Nullify();
03423   myToler = Precision::Confusion();
03424   myUseBoundaries = false;
03425 }
03426 
03427 ElementsOnSurface::~ElementsOnSurface()
03428 {
03429   myMesh = 0;
03430 }
03431 
03432 void ElementsOnSurface::SetMesh( const SMDS_Mesh* theMesh )
03433 {
03434   if ( myMesh == theMesh )
03435     return;
03436   myMesh = theMesh;
03437   process();
03438 }
03439 
03440 bool ElementsOnSurface::IsSatisfy( long theElementId )
03441 {
03442   return myIds.Contains( theElementId );
03443 }
03444 
03445 SMDSAbs_ElementType ElementsOnSurface::GetType() const
03446 { return myType; }
03447 
03448 void ElementsOnSurface::SetTolerance( const double theToler )
03449 {
03450   if ( myToler != theToler )
03451     myIds.Clear();
03452   myToler = theToler;
03453 }
03454 
03455 double ElementsOnSurface::GetTolerance() const
03456 { return myToler; }
03457 
03458 void ElementsOnSurface::SetUseBoundaries( bool theUse )
03459 {
03460   if ( myUseBoundaries != theUse ) {
03461     myUseBoundaries = theUse;
03462     SetSurface( mySurf, myType );
03463   }
03464 }
03465 
03466 void ElementsOnSurface::SetSurface( const TopoDS_Shape& theShape,
03467                                     const SMDSAbs_ElementType theType )
03468 {
03469   myIds.Clear();
03470   myType = theType;
03471   mySurf.Nullify();
03472   if ( theShape.IsNull() || theShape.ShapeType() != TopAbs_FACE )
03473     return;
03474   mySurf = TopoDS::Face( theShape );
03475   BRepAdaptor_Surface SA( mySurf, myUseBoundaries );
03476   Standard_Real
03477     u1 = SA.FirstUParameter(),
03478     u2 = SA.LastUParameter(),
03479     v1 = SA.FirstVParameter(),
03480     v2 = SA.LastVParameter();
03481   Handle(Geom_Surface) surf = BRep_Tool::Surface( mySurf );
03482   myProjector.Init( surf, u1,u2, v1,v2 );
03483   process();
03484 }
03485 
03486 void ElementsOnSurface::process()
03487 {
03488   myIds.Clear();
03489   if ( mySurf.IsNull() )
03490     return;
03491 
03492   if ( myMesh == 0 )
03493     return;
03494 
03495   if ( myType == SMDSAbs_Face || myType == SMDSAbs_All )
03496   {
03497     myIds.ReSize( myMesh->NbFaces() );
03498     SMDS_FaceIteratorPtr anIter = myMesh->facesIterator();
03499     for(; anIter->more(); )
03500       process( anIter->next() );
03501   }
03502 
03503   if ( myType == SMDSAbs_Edge || myType == SMDSAbs_All )
03504   {
03505     myIds.ReSize( myIds.Extent() + myMesh->NbEdges() );
03506     SMDS_EdgeIteratorPtr anIter = myMesh->edgesIterator();
03507     for(; anIter->more(); )
03508       process( anIter->next() );
03509   }
03510 
03511   if ( myType == SMDSAbs_Node )
03512   {
03513     myIds.ReSize( myMesh->NbNodes() );
03514     SMDS_NodeIteratorPtr anIter = myMesh->nodesIterator();
03515     for(; anIter->more(); )
03516       process( anIter->next() );
03517   }
03518 }
03519 
03520 void ElementsOnSurface::process( const SMDS_MeshElement* theElemPtr )
03521 {
03522   SMDS_ElemIteratorPtr aNodeItr = theElemPtr->nodesIterator();
03523   bool isSatisfy = true;
03524   for ( ; aNodeItr->more(); )
03525   {
03526     SMDS_MeshNode* aNode = (SMDS_MeshNode*)aNodeItr->next();
03527     if ( !isOnSurface( aNode ) )
03528     {
03529       isSatisfy = false;
03530       break;
03531     }
03532   }
03533   if ( isSatisfy )
03534     myIds.Add( theElemPtr->GetID() );
03535 }
03536 
03537 bool ElementsOnSurface::isOnSurface( const SMDS_MeshNode* theNode )
03538 {
03539   if ( mySurf.IsNull() )
03540     return false;
03541 
03542   gp_Pnt aPnt( theNode->X(), theNode->Y(), theNode->Z() );
03543   //  double aToler2 = myToler * myToler;
03544 //   if ( mySurf->IsKind(STANDARD_TYPE(Geom_Plane)))
03545 //   {
03546 //     gp_Pln aPln = Handle(Geom_Plane)::DownCast(mySurf)->Pln();
03547 //     if ( aPln.SquareDistance( aPnt ) > aToler2 )
03548 //       return false;
03549 //   }
03550 //   else if ( mySurf->IsKind(STANDARD_TYPE(Geom_CylindricalSurface)))
03551 //   {
03552 //     gp_Cylinder aCyl = Handle(Geom_CylindricalSurface)::DownCast(mySurf)->Cylinder();
03553 //     double aRad = aCyl.Radius();
03554 //     gp_Ax3 anAxis = aCyl.Position();
03555 //     gp_XYZ aLoc = aCyl.Location().XYZ();
03556 //     double aXDist = anAxis.XDirection().XYZ() * ( aPnt.XYZ() - aLoc );
03557 //     double aYDist = anAxis.YDirection().XYZ() * ( aPnt.XYZ() - aLoc );
03558 //     if ( fabs(aXDist*aXDist + aYDist*aYDist - aRad*aRad) > aToler2 )
03559 //       return false;
03560 //   }
03561 //   else
03562 //     return false;
03563   myProjector.Perform( aPnt );
03564   bool isOn = ( myProjector.IsDone() && myProjector.LowerDistance() <= myToler );
03565 
03566   return isOn;
03567 }
03568 
03569 
03570 /*
03571   ElementsOnShape
03572 */
03573 
03574 ElementsOnShape::ElementsOnShape()
03575   : myMesh(0),
03576     myType(SMDSAbs_All),
03577     myToler(Precision::Confusion()),
03578     myAllNodesFlag(false)
03579 {
03580   myCurShapeType = TopAbs_SHAPE;
03581 }
03582 
03583 ElementsOnShape::~ElementsOnShape()
03584 {
03585 }
03586 
03587 void ElementsOnShape::SetMesh (const SMDS_Mesh* theMesh)
03588 {
03589   if (myMesh != theMesh) {
03590     myMesh = theMesh;
03591     SetShape(myShape, myType);
03592   }
03593 }
03594 
03595 bool ElementsOnShape::IsSatisfy (long theElementId)
03596 {
03597   return myIds.Contains(theElementId);
03598 }
03599 
03600 SMDSAbs_ElementType ElementsOnShape::GetType() const
03601 {
03602   return myType;
03603 }
03604 
03605 void ElementsOnShape::SetTolerance (const double theToler)
03606 {
03607   if (myToler != theToler) {
03608     myToler = theToler;
03609     SetShape(myShape, myType);
03610   }
03611 }
03612 
03613 double ElementsOnShape::GetTolerance() const
03614 {
03615   return myToler;
03616 }
03617 
03618 void ElementsOnShape::SetAllNodes (bool theAllNodes)
03619 {
03620   if (myAllNodesFlag != theAllNodes) {
03621     myAllNodesFlag = theAllNodes;
03622     SetShape(myShape, myType);
03623   }
03624 }
03625 
03626 void ElementsOnShape::SetShape (const TopoDS_Shape&       theShape,
03627                                 const SMDSAbs_ElementType theType)
03628 {
03629   myType = theType;
03630   myShape = theShape;
03631   myIds.Clear();
03632 
03633   if (myMesh == 0) return;
03634 
03635   switch (myType)
03636   {
03637   case SMDSAbs_All:
03638     myIds.ReSize(myMesh->NbEdges() + myMesh->NbFaces() + myMesh->NbVolumes());
03639     break;
03640   case SMDSAbs_Node:
03641     myIds.ReSize(myMesh->NbNodes());
03642     break;
03643   case SMDSAbs_Edge:
03644     myIds.ReSize(myMesh->NbEdges());
03645     break;
03646   case SMDSAbs_Face:
03647     myIds.ReSize(myMesh->NbFaces());
03648     break;
03649   case SMDSAbs_Volume:
03650     myIds.ReSize(myMesh->NbVolumes());
03651     break;
03652   default:
03653     break;
03654   }
03655 
03656   myShapesMap.Clear();
03657   addShape(myShape);
03658 }
03659 
03660 void ElementsOnShape::addShape (const TopoDS_Shape& theShape)
03661 {
03662   if (theShape.IsNull() || myMesh == 0)
03663     return;
03664 
03665   if (!myShapesMap.Add(theShape)) return;
03666 
03667   myCurShapeType = theShape.ShapeType();
03668   switch (myCurShapeType)
03669   {
03670   case TopAbs_COMPOUND:
03671   case TopAbs_COMPSOLID:
03672   case TopAbs_SHELL:
03673   case TopAbs_WIRE:
03674     {
03675       TopoDS_Iterator anIt (theShape, Standard_True, Standard_True);
03676       for (; anIt.More(); anIt.Next()) addShape(anIt.Value());
03677     }
03678     break;
03679   case TopAbs_SOLID:
03680     {
03681       myCurSC.Load(theShape);
03682       process();
03683     }
03684     break;
03685   case TopAbs_FACE:
03686     {
03687       TopoDS_Face aFace = TopoDS::Face(theShape);
03688       BRepAdaptor_Surface SA (aFace, true);
03689       Standard_Real
03690         u1 = SA.FirstUParameter(),
03691         u2 = SA.LastUParameter(),
03692         v1 = SA.FirstVParameter(),
03693         v2 = SA.LastVParameter();
03694       Handle(Geom_Surface) surf = BRep_Tool::Surface(aFace);
03695       myCurProjFace.Init(surf, u1,u2, v1,v2);
03696       myCurFace = aFace;
03697       process();
03698     }
03699     break;
03700   case TopAbs_EDGE:
03701     {
03702       TopoDS_Edge anEdge = TopoDS::Edge(theShape);
03703       Standard_Real u1, u2;
03704       Handle(Geom_Curve) curve = BRep_Tool::Curve(anEdge, u1, u2);
03705       myCurProjEdge.Init(curve, u1, u2);
03706       process();
03707     }
03708     break;
03709   case TopAbs_VERTEX:
03710     {
03711       TopoDS_Vertex aV = TopoDS::Vertex(theShape);
03712       myCurPnt = BRep_Tool::Pnt(aV);
03713       process();
03714     }
03715     break;
03716   default:
03717     break;
03718   }
03719 }
03720 
03721 void ElementsOnShape::process()
03722 {
03723   if (myShape.IsNull() || myMesh == 0)
03724     return;
03725 
03726   if (myType == SMDSAbs_Node)
03727   {
03728     SMDS_NodeIteratorPtr anIter = myMesh->nodesIterator();
03729     while (anIter->more())
03730       process(anIter->next());
03731   }
03732   else
03733   {
03734     if (myType == SMDSAbs_Edge || myType == SMDSAbs_All)
03735     {
03736       SMDS_EdgeIteratorPtr anIter = myMesh->edgesIterator();
03737       while (anIter->more())
03738         process(anIter->next());
03739     }
03740 
03741     if (myType == SMDSAbs_Face || myType == SMDSAbs_All)
03742     {
03743       SMDS_FaceIteratorPtr anIter = myMesh->facesIterator();
03744       while (anIter->more()) {
03745         process(anIter->next());
03746       }
03747     }
03748 
03749     if (myType == SMDSAbs_Volume || myType == SMDSAbs_All)
03750     {
03751       SMDS_VolumeIteratorPtr anIter = myMesh->volumesIterator();
03752       while (anIter->more())
03753         process(anIter->next());
03754     }
03755   }
03756 }
03757 
03758 void ElementsOnShape::process (const SMDS_MeshElement* theElemPtr)
03759 {
03760   if (myShape.IsNull())
03761     return;
03762 
03763   SMDS_ElemIteratorPtr aNodeItr = theElemPtr->nodesIterator();
03764   bool isSatisfy = myAllNodesFlag;
03765 
03766   gp_XYZ centerXYZ (0, 0, 0);
03767 
03768   while (aNodeItr->more() && (isSatisfy == myAllNodesFlag))
03769   {
03770     SMDS_MeshNode* aNode = (SMDS_MeshNode*)aNodeItr->next();
03771     gp_Pnt aPnt (aNode->X(), aNode->Y(), aNode->Z());
03772     centerXYZ += aPnt.XYZ();
03773 
03774     switch (myCurShapeType)
03775     {
03776     case TopAbs_SOLID:
03777       {
03778         myCurSC.Perform(aPnt, myToler);
03779         isSatisfy = (myCurSC.State() == TopAbs_IN || myCurSC.State() == TopAbs_ON);
03780       }
03781       break;
03782     case TopAbs_FACE:
03783       {
03784         myCurProjFace.Perform(aPnt);
03785         isSatisfy = (myCurProjFace.IsDone() && myCurProjFace.LowerDistance() <= myToler);
03786         if (isSatisfy)
03787         {
03788           // check relatively the face
03789           Quantity_Parameter u, v;
03790           myCurProjFace.LowerDistanceParameters(u, v);
03791           gp_Pnt2d aProjPnt (u, v);
03792           BRepClass_FaceClassifier aClsf (myCurFace, aProjPnt, myToler);
03793           isSatisfy = (aClsf.State() == TopAbs_IN || aClsf.State() == TopAbs_ON);
03794         }
03795       }
03796       break;
03797     case TopAbs_EDGE:
03798       {
03799         myCurProjEdge.Perform(aPnt);
03800         isSatisfy = (myCurProjEdge.NbPoints() > 0 && myCurProjEdge.LowerDistance() <= myToler);
03801       }
03802       break;
03803     case TopAbs_VERTEX:
03804       {
03805         isSatisfy = (aPnt.Distance(myCurPnt) <= myToler);
03806       }
03807       break;
03808     default:
03809       {
03810         isSatisfy = false;
03811       }
03812     }
03813   }
03814 
03815   if (isSatisfy && myCurShapeType == TopAbs_SOLID) { // Check the center point for volumes MantisBug 0020168
03816     centerXYZ /= theElemPtr->NbNodes();
03817     gp_Pnt aCenterPnt (centerXYZ);
03818     myCurSC.Perform(aCenterPnt, myToler);
03819     if ( !(myCurSC.State() == TopAbs_IN || myCurSC.State() == TopAbs_ON))
03820       isSatisfy = false;
03821   }
03822 
03823   if (isSatisfy)
03824     myIds.Add(theElemPtr->GetID());
03825 }
03826 
03827 TSequenceOfXYZ::TSequenceOfXYZ()
03828 {}
03829 
03830 TSequenceOfXYZ::TSequenceOfXYZ(size_type n) : myArray(n)
03831 {}
03832 
03833 TSequenceOfXYZ::TSequenceOfXYZ(size_type n, const gp_XYZ& t) : myArray(n,t)
03834 {}
03835 
03836 TSequenceOfXYZ::TSequenceOfXYZ(const TSequenceOfXYZ& theSequenceOfXYZ) : myArray(theSequenceOfXYZ.myArray)
03837 {}
03838 
03839 template <class InputIterator>
03840 TSequenceOfXYZ::TSequenceOfXYZ(InputIterator theBegin, InputIterator theEnd): myArray(theBegin,theEnd)
03841 {}
03842 
03843 TSequenceOfXYZ::~TSequenceOfXYZ()
03844 {}
03845 
03846 TSequenceOfXYZ& TSequenceOfXYZ::operator=(const TSequenceOfXYZ& theSequenceOfXYZ)
03847 {
03848   myArray = theSequenceOfXYZ.myArray;
03849   return *this;
03850 }
03851 
03852 gp_XYZ& TSequenceOfXYZ::operator()(size_type n)
03853 {
03854   return myArray[n-1];
03855 }
03856 
03857 const gp_XYZ& TSequenceOfXYZ::operator()(size_type n) const
03858 {
03859   return myArray[n-1];
03860 }
03861 
03862 void TSequenceOfXYZ::clear()
03863 {
03864   myArray.clear();
03865 }
03866 
03867 void TSequenceOfXYZ::reserve(size_type n)
03868 {
03869   myArray.reserve(n);
03870 }
03871 
03872 void TSequenceOfXYZ::push_back(const gp_XYZ& v)
03873 {
03874   myArray.push_back(v);
03875 }
03876 
03877 TSequenceOfXYZ::size_type TSequenceOfXYZ::size() const
03878 {
03879   return myArray.size();
03880 }
Copyright © 2007-2011 CEA/DEN, EDF R&D, OPEN CASCADE
Copyright © 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS