Salome HOME
Compute Progress bar
[modules/smesh.git] / src / SMESH / SMESH_Algo.cxx
1 // Copyright (C) 2007-2013  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 //  SMESH SMESH : implementaion of SMESH idl descriptions
24 //  File   : SMESH_Algo.cxx
25 //  Author : Paul RASCLE, EDF
26 //  Module : SMESH
27
28 #include "SMESH_Algo.hxx"
29
30 #include "SMDS_EdgePosition.hxx"
31 #include "SMDS_FacePosition.hxx"
32 #include "SMDS_MeshElement.hxx"
33 #include "SMDS_MeshNode.hxx"
34 #include "SMDS_VolumeTool.hxx"
35 #include "SMESHDS_Mesh.hxx"
36 #include "SMESHDS_SubMesh.hxx"
37 #include "SMESH_Comment.hxx"
38 #include "SMESH_Gen.hxx"
39 #include "SMESH_HypoFilter.hxx"
40 #include "SMESH_Mesh.hxx"
41 #include "SMESH_TypeDefs.hxx"
42 #include "SMESH_subMesh.hxx"
43
44 #include <Basics_OCCTVersion.hxx>
45
46 #include <BRepAdaptor_Curve.hxx>
47 #include <BRepLProp.hxx>
48 #include <BRep_Tool.hxx>
49 #include <GCPnts_AbscissaPoint.hxx>
50 #include <GeomAdaptor_Curve.hxx>
51 #include <Geom_Surface.hxx>
52 #include <LDOMParser.hxx>
53 #include <TopExp.hxx>
54 #include <TopExp_Explorer.hxx>
55 #include <TopLoc_Location.hxx>
56 #include <TopTools_ListIteratorOfListOfShape.hxx>
57 #include <TopTools_ListOfShape.hxx>
58 #include <TopoDS.hxx>
59 #include <TopoDS_Edge.hxx>
60 #include <TopoDS_Face.hxx>
61 #include <TopoDS_Vertex.hxx>
62 #include <TopoDS_Wire.hxx>
63 #include <gp_Pnt.hxx>
64 #include <gp_Pnt2d.hxx>
65 #include <gp_Vec.hxx>
66
67 #include <Standard_ErrorHandler.hxx>
68 #include <Standard_Failure.hxx>
69
70 #include "utilities.h"
71
72 #include <algorithm>
73 #include <limits>
74
75 using namespace std;
76
77 //================================================================================
78 /*!
79  * \brief Returns \a true if two algorithms (described by \a this and the given
80  *        algo data) are compatible by their output and input types of elements.
81  */
82 //================================================================================
83
84 bool SMESH_Algo::Features::IsCompatible( const SMESH_Algo::Features& algo2 ) const
85 {
86   if ( _dim > algo2._dim ) return algo2.IsCompatible( *this );
87   // algo2 is of highter dimension
88   if ( _outElemTypes.empty() || algo2._inElemTypes.empty() )
89     return false;
90   bool compatible = true;
91   set<SMDSAbs_GeometryType>::const_iterator myOutType = _outElemTypes.begin();
92   for ( ; myOutType != _outElemTypes.end() && compatible; ++myOutType )
93     compatible = algo2._inElemTypes.count( *myOutType );
94   return compatible;
95 }
96
97 //================================================================================
98 /*!
99  * \brief Return Data of the algorithm
100  */
101 //================================================================================
102
103 const SMESH_Algo::Features& SMESH_Algo::GetFeatures( const std::string& algoType )
104 {
105   static map< string, SMESH_Algo::Features > theFeaturesByName;
106   if ( theFeaturesByName.empty() )
107   {
108     // Read Plugin.xml files
109     vector< string > xmlPaths = SMESH_Gen::GetPluginXMLPaths();
110     LDOMParser xmlParser;
111     for ( size_t iXML = 0; iXML < xmlPaths.size(); ++iXML )
112     {
113       bool error = xmlParser.parse( xmlPaths[iXML].c_str() );
114       if ( error )
115       {
116         TCollection_AsciiString data;
117         INFOS( xmlParser.GetError(data) );
118         continue;
119       }
120       // <algorithm type="Regular_1D"
121       //            ...
122       //            input="EDGE"
123       //            output="QUAD,TRIA">
124       //
125       LDOM_Document xmlDoc = xmlParser.getDocument();
126       LDOM_NodeList algoNodeList = xmlDoc.getElementsByTagName( "algorithm" );
127       for ( int i = 0; i < algoNodeList.getLength(); ++i )
128       {
129         LDOM_Node     algoNode           = algoNodeList.item( i );
130         LDOM_Element& algoElem           = (LDOM_Element&) algoNode;
131         TCollection_AsciiString algoType = algoElem.getAttribute("type");
132         TCollection_AsciiString input    = algoElem.getAttribute("input");
133         TCollection_AsciiString output   = algoElem.getAttribute("output");
134         TCollection_AsciiString dim      = algoElem.getAttribute("dim");
135         TCollection_AsciiString label    = algoElem.getAttribute("label-id");
136         if ( algoType.IsEmpty() ) continue;
137
138         Features & data = theFeaturesByName[ algoType.ToCString() ];
139         data._dim   = dim.IntegerValue();
140         data._label = label.ToCString();
141         for ( int isInput = 0; isInput < 2; ++isInput )
142         {
143           TCollection_AsciiString&   typeStr = isInput ? input : output;
144           set<SMDSAbs_GeometryType>& typeSet = isInput ? data._inElemTypes : data._outElemTypes;
145           int beg = 1, end;
146           while ( beg <= typeStr.Length() )
147           {
148             while ( beg < typeStr.Length() && !isalpha( typeStr.Value( beg ) ))
149               ++beg;
150             end = beg;
151             while ( end < typeStr.Length() && isalpha( typeStr.Value( end + 1 ) ))
152               ++end;
153             if ( end > beg )
154             {
155               TCollection_AsciiString typeName = typeStr.SubString( beg, end );
156               if      ( typeName == "EDGE" ) typeSet.insert( SMDSGeom_EDGE );
157               else if ( typeName == "TRIA" ) typeSet.insert( SMDSGeom_TRIANGLE );
158               else if ( typeName == "QUAD" ) typeSet.insert( SMDSGeom_QUADRANGLE );
159             }
160             beg = end + 1;
161           }
162         }
163       }
164     }
165   }
166   return theFeaturesByName[ algoType ];
167 }
168
169 //=============================================================================
170 /*!
171  *  
172  */
173 //=============================================================================
174
175 SMESH_Algo::SMESH_Algo (int hypId, int studyId, SMESH_Gen * gen)
176   : SMESH_Hypothesis(hypId, studyId, gen)
177 {
178   //gen->_mapAlgo[hypId] = this;
179
180   _onlyUnaryInput = _requireDiscreteBoundary = _requireShape = true;
181   _quadraticMesh = _supportSubmeshes = false;
182   _error = COMPERR_OK;
183   for ( int i = 0; i < 4; ++i )
184     _neededLowerHyps[ i ] = false;
185 }
186
187 //=============================================================================
188 /*!
189  *  
190  */
191 //=============================================================================
192
193 SMESH_Algo::~SMESH_Algo()
194 {
195 }
196
197 //=============================================================================
198 /*!
199  *  
200  */
201 //=============================================================================
202
203 SMESH_0D_Algo::SMESH_0D_Algo(int hypId, int studyId, SMESH_Gen* gen)
204   : SMESH_Algo(hypId, studyId, gen)
205 {
206   _shapeType = (1 << TopAbs_VERTEX);
207   _type = ALGO_0D;
208   //gen->_map0D_Algo[hypId] = this;
209 }
210 SMESH_1D_Algo::SMESH_1D_Algo(int hypId, int studyId, SMESH_Gen* gen)
211   : SMESH_Algo(hypId, studyId, gen)
212 {
213   _shapeType = (1 << TopAbs_EDGE);
214   _type = ALGO_1D;
215   //gen->_map1D_Algo[hypId] = this;
216 }
217 SMESH_2D_Algo::SMESH_2D_Algo(int hypId, int studyId, SMESH_Gen* gen)
218   : SMESH_Algo(hypId, studyId, gen)
219 {
220   _shapeType = (1 << TopAbs_FACE);
221   _type = ALGO_2D;
222   //gen->_map2D_Algo[hypId] = this;
223 }
224 SMESH_3D_Algo::SMESH_3D_Algo(int hypId, int studyId, SMESH_Gen* gen)
225   : SMESH_Algo(hypId, studyId, gen)
226 {
227   _shapeType = (1 << TopAbs_SOLID);
228   _type = ALGO_3D;
229   //gen->_map3D_Algo[hypId] = this;
230 }
231
232 //=============================================================================
233 /*!
234  * Usually an algoritm has nothing to save
235  */
236 //=============================================================================
237
238 ostream & SMESH_Algo::SaveTo(ostream & save) { return save; }
239 istream & SMESH_Algo::LoadFrom(istream & load) { return load; }
240
241 //=============================================================================
242 /*!
243  *  
244  */
245 //=============================================================================
246
247 const vector < string > &SMESH_Algo::GetCompatibleHypothesis()
248 {
249   return _compatibleHypothesis;
250 }
251
252 //=============================================================================
253 /*!
254  *  List the hypothesis used by the algorithm associated to the shape.
255  *  Hypothesis associated to father shape -are- taken into account (see
256  *  GetAppliedHypothesis). Relevant hypothesis have a name (type) listed in
257  *  the algorithm. This method could be surcharged by specific algorithms, in 
258  *  case of several hypothesis simultaneously applicable.
259  */
260 //=============================================================================
261
262 const list <const SMESHDS_Hypothesis *> &
263 SMESH_Algo::GetUsedHypothesis(SMESH_Mesh &         aMesh,
264                               const TopoDS_Shape & aShape,
265                               const bool           ignoreAuxiliary) const
266 {
267   SMESH_Algo* me = const_cast< SMESH_Algo* >( this );
268   me->_usedHypList.clear();
269   SMESH_HypoFilter filter;
270   if ( InitCompatibleHypoFilter( filter, ignoreAuxiliary ))
271   {
272     aMesh.GetHypotheses( aShape, filter, me->_usedHypList, true );
273     if ( ignoreAuxiliary && _usedHypList.size() > 1 )
274       me->_usedHypList.clear(); //only one compatible hypothesis allowed
275   }
276   return _usedHypList;
277 }
278
279 //=============================================================================
280 /*!
281  *  List the relevant hypothesis associated to the shape. Relevant hypothesis
282  *  have a name (type) listed in the algorithm. Hypothesis associated to
283  *  father shape -are not- taken into account (see GetUsedHypothesis)
284  */
285 //=============================================================================
286
287 const list<const SMESHDS_Hypothesis *> &
288 SMESH_Algo::GetAppliedHypothesis(SMESH_Mesh &         aMesh,
289                                  const TopoDS_Shape & aShape,
290                                  const bool           ignoreAuxiliary) const
291 {
292   SMESH_Algo* me = const_cast< SMESH_Algo* >( this );
293   me->_appliedHypList.clear();
294   SMESH_HypoFilter filter;
295   if ( InitCompatibleHypoFilter( filter, ignoreAuxiliary ))
296     aMesh.GetHypotheses( aShape, filter, me->_appliedHypList, false );
297
298   return _appliedHypList;
299 }
300
301 //=============================================================================
302 /*!
303  *  Compute length of an edge
304  */
305 //=============================================================================
306
307 double SMESH_Algo::EdgeLength(const TopoDS_Edge & E)
308 {
309   double UMin = 0, UMax = 0;
310   if (BRep_Tool::Degenerated(E))
311     return 0;
312   TopLoc_Location L;
313   Handle(Geom_Curve) C = BRep_Tool::Curve(E, L, UMin, UMax);
314   GeomAdaptor_Curve AdaptCurve(C, UMin, UMax); //range is important for periodic curves
315   double length = GCPnts_AbscissaPoint::Length(AdaptCurve, UMin, UMax);
316   return length;
317 }
318
319 //================================================================================
320 /*!
321  * \brief Just return false as the algorithm does not hold parameters values
322  */
323 //================================================================================
324
325 bool SMESH_Algo::SetParametersByMesh(const SMESH_Mesh* /*theMesh*/,
326                                      const TopoDS_Shape& /*theShape*/)
327 {
328   return false;
329 }
330 bool SMESH_Algo::SetParametersByDefaults(const TDefaults& , const SMESH_Mesh*)
331 {
332   return false;
333 }
334 //================================================================================
335 /*!
336  * \brief Fill vector of node parameters on geometrical edge, including vertex nodes
337  * \param theMesh - The mesh containing nodes
338  * \param theEdge - The geometrical edge of interest
339  * \param theParams - The resulting vector of sorted node parameters
340  * \retval bool - false if not all parameters are OK
341  */
342 //================================================================================
343
344 bool SMESH_Algo::GetNodeParamOnEdge(const SMESHDS_Mesh* theMesh,
345                                     const TopoDS_Edge&  theEdge,
346                                     vector< double > &  theParams)
347 {
348   theParams.clear();
349
350   if ( !theMesh || theEdge.IsNull() )
351     return false;
352
353   SMESHDS_SubMesh * eSubMesh = theMesh->MeshElements( theEdge );
354   if ( !eSubMesh || !eSubMesh->GetElements()->more() )
355     return false; // edge is not meshed
356
357   //int nbEdgeNodes = 0;
358   set < double > paramSet;
359   if ( eSubMesh )
360   {
361     // loop on nodes of an edge: sort them by param on edge
362     SMDS_NodeIteratorPtr nIt = eSubMesh->GetNodes();
363     while ( nIt->more() )
364     {
365       const SMDS_MeshNode* node = nIt->next();
366       const SMDS_PositionPtr& pos = node->GetPosition();
367       if ( pos->GetTypeOfPosition() != SMDS_TOP_EDGE )
368         return false;
369       const SMDS_EdgePosition* epos =
370         static_cast<const SMDS_EdgePosition*>(node->GetPosition());
371       if ( !paramSet.insert( epos->GetUParameter() ).second )
372         return false; // equal parameters
373     }
374   }
375   // add vertex nodes params
376   TopoDS_Vertex V1,V2;
377   TopExp::Vertices( theEdge, V1, V2);
378   if ( VertexNode( V1, theMesh ) &&
379        !paramSet.insert( BRep_Tool::Parameter(V1,theEdge) ).second )
380     return false; // there are equal parameters
381   if ( VertexNode( V2, theMesh ) &&
382        !paramSet.insert( BRep_Tool::Parameter(V2,theEdge) ).second )
383     return false; // there are equal parameters
384
385   // fill the vector
386   theParams.resize( paramSet.size() );
387   set < double >::iterator   par    = paramSet.begin();
388   vector< double >::iterator vecPar = theParams.begin();
389   for ( ; par != paramSet.end(); ++par, ++vecPar )
390     *vecPar = *par;
391
392   return theParams.size() > 1;
393 }
394
395 //================================================================================
396 /*!
397  * \brief Fill vector of node parameters on geometrical edge, including vertex nodes
398  * \param theMesh - The mesh containing nodes
399  * \param theEdge - The geometrical edge of interest
400  * \param theParams - The resulting vector of sorted node parameters
401  * \retval bool - false if not all parameters are OK
402  */
403 //================================================================================
404
405 bool SMESH_Algo::GetSortedNodesOnEdge(const SMESHDS_Mesh*                   theMesh,
406                                       const TopoDS_Edge&                    theEdge,
407                                       const bool                            ignoreMediumNodes,
408                                       map< double, const SMDS_MeshNode* > & theNodes)
409 {
410   theNodes.clear();
411
412   if ( !theMesh || theEdge.IsNull() )
413     return false;
414
415   SMESHDS_SubMesh * eSubMesh = theMesh->MeshElements( theEdge );
416   if ( !eSubMesh || !eSubMesh->GetElements()->more() )
417     return false; // edge is not meshed
418
419   int nbNodes = 0;
420   set < double > paramSet;
421   if ( eSubMesh )
422   {
423     // loop on nodes of an edge: sort them by param on edge
424     SMDS_NodeIteratorPtr nIt = eSubMesh->GetNodes();
425     while ( nIt->more() )
426     {
427       const SMDS_MeshNode* node = nIt->next();
428       if ( ignoreMediumNodes ) {
429         SMDS_ElemIteratorPtr elemIt = node->GetInverseElementIterator();
430         if ( elemIt->more() && elemIt->next()->IsMediumNode( node ))
431           continue;
432       }
433       const SMDS_PositionPtr& pos = node->GetPosition();
434       if ( pos->GetTypeOfPosition() != SMDS_TOP_EDGE )
435         return false;
436       const SMDS_EdgePosition* epos =
437         static_cast<const SMDS_EdgePosition*>(node->GetPosition());
438       theNodes.insert( theNodes.end(), make_pair( epos->GetUParameter(), node ));
439       //MESSAGE("U " << epos->GetUParameter() << " ID " << node->GetID());
440       ++nbNodes;
441     }
442   }
443   // add vertex nodes
444   TopoDS_Vertex v1, v2;
445   TopExp::Vertices(theEdge, v1, v2);
446   const SMDS_MeshNode* n1 = VertexNode( v1, (SMESHDS_Mesh*) theMesh );
447   const SMDS_MeshNode* n2 = VertexNode( v2, (SMESHDS_Mesh*) theMesh );
448   //MESSAGE("Vertices ID " << n1->GetID() << " " << n2->GetID());
449   Standard_Real f, l;
450   BRep_Tool::Range(theEdge, f, l);
451   if ( v1.Orientation() != TopAbs_FORWARD )
452     std::swap( f, l );
453   if ( n1 && ++nbNodes )
454     theNodes.insert( make_pair( f, n1 ));
455   if ( n2 && ++nbNodes )
456     theNodes.insert( make_pair( l, n2 ));
457
458   return theNodes.size() == nbNodes;
459 }
460
461 //================================================================================
462 /*!
463  * \brief Make filter recognize only compatible hypotheses
464  * \param theFilter - the filter to initialize
465  * \param ignoreAuxiliary - make filter ignore compatible auxiliary hypotheses
466  */
467 //================================================================================
468
469 bool SMESH_Algo::InitCompatibleHypoFilter( SMESH_HypoFilter & theFilter,
470                                            const bool         ignoreAuxiliary) const
471 {
472   if ( !_compatibleHypothesis.empty() )
473   {
474     theFilter.Init( theFilter.HasName( _compatibleHypothesis[0] ));
475     for ( int i = 1; i < _compatibleHypothesis.size(); ++i )
476       theFilter.Or( theFilter.HasName( _compatibleHypothesis[ i ] ));
477
478     if ( ignoreAuxiliary )
479       theFilter.AndNot( theFilter.IsAuxiliary() );
480
481     return true;
482   }
483   return false;
484 }
485
486 //================================================================================
487 /*!
488  * \brief Return continuity of two edges
489  * \param E1 - the 1st edge
490  * \param E2 - the 2nd edge
491  * \retval GeomAbs_Shape - regularity at the junction between E1 and E2
492  */
493 //================================================================================
494
495 GeomAbs_Shape SMESH_Algo::Continuity(TopoDS_Edge E1,
496                                      TopoDS_Edge E2)
497 {
498   //E1.Orientation(TopAbs_FORWARD), E2.Orientation(TopAbs_FORWARD); // avoid pb with internal edges
499   if (E1.Orientation() > TopAbs_REVERSED) // INTERNAL
500     E1.Orientation( TopAbs_FORWARD );
501   if (E2.Orientation() > TopAbs_REVERSED) // INTERNAL
502     E2.Orientation( TopAbs_FORWARD );
503
504   TopoDS_Vertex V, VV1[2], VV2[2];
505   TopExp::Vertices( E1, VV1[0], VV1[1], true );
506   TopExp::Vertices( E2, VV2[0], VV2[1], true );
507   if      ( VV1[1].IsSame( VV2[0] ))  { V = VV1[1]; }
508   else if ( VV1[0].IsSame( VV2[1] ))  { V = VV1[0]; }
509   else if ( VV1[1].IsSame( VV2[1] ))  { V = VV1[1]; E1.Reverse(); }
510   else if ( VV1[0].IsSame( VV2[0] ))  { V = VV1[0]; E1.Reverse(); }
511   else { return GeomAbs_C0; }
512
513   Standard_Real u1 = BRep_Tool::Parameter( V, E1 );
514   Standard_Real u2 = BRep_Tool::Parameter( V, E2 );
515   BRepAdaptor_Curve C1( E1 ), C2( E2 );
516   Standard_Real tol = BRep_Tool::Tolerance( V );
517   Standard_Real angTol = 2e-3;
518   try {
519 #if OCC_VERSION_LARGE > 0x06010000
520     OCC_CATCH_SIGNALS;
521 #endif
522     return BRepLProp::Continuity(C1, C2, u1, u2, tol, angTol);
523   }
524   catch (Standard_Failure) {
525   }
526   return GeomAbs_C0;
527 }
528
529 //================================================================================
530 /*!
531  * \brief Return the node built on a vertex
532  * \param V - the vertex
533  * \param meshDS - mesh
534  * \retval const SMDS_MeshNode* - found node or NULL
535  */
536 //================================================================================
537
538 const SMDS_MeshNode* SMESH_Algo::VertexNode(const TopoDS_Vertex& V,
539                                             const SMESHDS_Mesh*  meshDS)
540 {
541   if ( SMESHDS_SubMesh* sm = meshDS->MeshElements(V) ) {
542     SMDS_NodeIteratorPtr nIt= sm->GetNodes();
543     if (nIt->more())
544       return nIt->next();
545   }
546   return 0;
547 }
548
549 //=======================================================================
550 //function : GetMeshError
551 //purpose  : Finds topological errors of a sub-mesh
552 //WARNING  : 1D check is NOT implemented so far
553 //=======================================================================
554
555 SMESH_Algo::EMeshError SMESH_Algo::GetMeshError(SMESH_subMesh* subMesh)
556 {
557   EMeshError err = MEr_OK;
558
559   SMESHDS_SubMesh* smDS = subMesh->GetSubMeshDS();
560   if ( !smDS )
561     return MEr_EMPTY;
562
563   switch ( subMesh->GetSubShape().ShapeType() )
564   {
565   case TopAbs_FACE: { // ====================== 2D =====================
566
567     SMDS_ElemIteratorPtr fIt = smDS->GetElements();
568     if ( !fIt->more() )
569       return MEr_EMPTY;
570
571     // We check that olny links on EDGEs encouter once, the rest links, twice
572     set< SMESH_TLink > links;
573     while ( fIt->more() )
574     {
575       const SMDS_MeshElement* f = fIt->next();
576       int nbNodes = f->NbCornerNodes(); // ignore medium nodes
577       for ( int i = 0; i < nbNodes; ++i )
578       {
579         const SMDS_MeshNode* n1 = f->GetNode( i );
580         const SMDS_MeshNode* n2 = f->GetNode(( i+1 ) % nbNodes);
581         std::pair< set< SMESH_TLink >::iterator, bool > it_added =
582           links.insert( SMESH_TLink( n1, n2 ));
583         if ( !it_added.second )
584           // As we do NOT(!) check if mesh is manifold, we believe that a link can
585           // encounter once or twice only (not three times), we erase a link as soon
586           // as it encounters twice to speed up search in the <links> map.
587           links.erase( it_added.first );
588       }
589     }
590     // the links remaining in the <links> should all be on EDGE
591     set< SMESH_TLink >::iterator linkIt = links.begin();
592     for ( ; linkIt != links.end(); ++linkIt )
593     {
594       const SMESH_TLink& link = *linkIt;
595       if ( link.node1()->GetPosition()->GetTypeOfPosition() > SMDS_TOP_EDGE ||
596            link.node2()->GetPosition()->GetTypeOfPosition() > SMDS_TOP_EDGE )
597         return MEr_HOLES;
598     }
599     // TODO: to check orientation
600     break;
601   }
602   case TopAbs_SOLID: { // ====================== 3D =====================
603
604     SMDS_ElemIteratorPtr vIt = smDS->GetElements();
605     if ( !vIt->more() )
606       return MEr_EMPTY;
607
608     SMDS_VolumeTool vTool;
609     while ( !vIt->more() )
610     {
611       if (!vTool.Set( vIt->next() ))
612         continue; // strange
613
614       for ( int iF = 0; iF < vTool.NbFaces(); ++iF )
615         if ( vTool.IsFreeFace( iF ))
616         {
617           int nbN = vTool.NbFaceNodes( iF );
618           const SMDS_MeshNode** nodes =  vTool.GetFaceNodes( iF );
619           for ( int i = 0; i < nbN; ++i )
620             if ( nodes[i]->GetPosition()->GetTypeOfPosition() > SMDS_TOP_FACE )
621               return MEr_HOLES;
622         }
623     }
624     break;
625   }
626   default:;
627   }
628   return err;
629 }
630
631 //================================================================================
632 /*!
633  * \brief Sets event listener to submeshes if necessary
634  * \param subMesh - submesh where algo is set
635  * 
636  * After being set, event listener is notified on each event of a submesh.
637  * By default non listener is set
638  */
639 //================================================================================
640
641 void SMESH_Algo::SetEventListener(SMESH_subMesh* /*subMesh*/)
642 {
643 }
644
645 //================================================================================
646 /*!
647  * \brief Allow algo to do something after persistent restoration
648  * \param subMesh - restored submesh
649  *
650  * This method is called only if a submesh has HYP_OK algo_state.
651  */
652 //================================================================================
653
654 void SMESH_Algo::SubmeshRestored(SMESH_subMesh* /*subMesh*/)
655 {
656 }
657
658 //================================================================================
659 /*!
660  * \brief Computes mesh without geometry
661  * \param aMesh - the mesh
662  * \param aHelper - helper that must be used for adding elements to \aaMesh
663  * \retval bool - is a success
664  */
665 //================================================================================
666
667 bool SMESH_Algo::Compute(SMESH_Mesh & /*aMesh*/, SMESH_MesherHelper* /*aHelper*/)
668 {
669   return error( COMPERR_BAD_INPUT_MESH, "Mesh built on shape expected");
670 }
671
672 //=======================================================================
673 //function : CancelCompute
674 //purpose  : Sets _computeCanceled to true. It's usage depends on
675 //  *        implementation of a particular mesher.
676 //=======================================================================
677
678 void SMESH_Algo::CancelCompute()
679 {
680   _computeCanceled = true;
681   _error = COMPERR_CANCELED;
682 }
683
684 //================================================================================
685 /*
686  * If possible, returns progress of computation [0.,1.]
687  */
688 //================================================================================
689
690 double SMESH_Algo::GetProgress() const
691 {
692   return _progress;
693 }
694
695 //================================================================================
696 /*!
697  * \brief store error and comment and then return ( error == COMPERR_OK )
698  */
699 //================================================================================
700
701 bool SMESH_Algo::error(int error, const SMESH_Comment& comment)
702 {
703   _error   = error;
704   _comment = comment;
705   return ( error == COMPERR_OK );
706 }
707
708 //================================================================================
709 /*!
710  * \brief store error and return ( error == COMPERR_OK )
711  */
712 //================================================================================
713
714 bool SMESH_Algo::error(SMESH_ComputeErrorPtr error)
715 {
716   if ( error ) {
717     _error   = error->myName;
718     _comment = error->myComment;
719     _badInputElements = error->myBadElements;
720     return error->IsOK();
721   }
722   return true;
723 }
724
725 //================================================================================
726 /*!
727  * \brief return compute error
728  */
729 //================================================================================
730
731 SMESH_ComputeErrorPtr SMESH_Algo::GetComputeError() const
732 {
733   SMESH_ComputeErrorPtr err = SMESH_ComputeError::New( _error, _comment, this );
734   // hope this method is called by only SMESH_subMesh after this->Compute()
735   err->myBadElements.splice( err->myBadElements.end(),
736                              (list<const SMDS_MeshElement*>&) _badInputElements );
737   return err;
738 }
739
740 //================================================================================
741 /*!
742  * \brief initialize compute error before call of Compute()
743  */
744 //================================================================================
745
746 void SMESH_Algo::InitComputeError()
747 {
748   _error = COMPERR_OK;
749   _comment.clear();
750   list<const SMDS_MeshElement*>::iterator elem = _badInputElements.begin();
751   for ( ; elem != _badInputElements.end(); ++elem )
752     if ( (*elem)->GetID() < 1 )
753       delete *elem;
754   _badInputElements.clear();
755
756   _computeCanceled = false;
757   _progressTic     = 0;
758   _progress        = 0.;
759 }
760
761 //================================================================================
762 /*!
763  * \brief Return compute progress by nb of calls of this method
764  */
765 //================================================================================
766
767 double SMESH_Algo::GetProgressByTic() const
768 {
769   int computeCost = 0;
770   for ( size_t i = 0; i < _smToCompute.size(); ++i )
771     computeCost += _smToCompute[i]->GetComputeCost();
772
773   const_cast<SMESH_Algo*>( this )->_progressTic++;
774
775   double x = 5 * _progressTic;
776   x = ( x < computeCost ) ? ( x / computeCost ) : 1.;
777   return 0.9 * sin( x * M_PI / 2 );
778 }
779
780 //================================================================================
781 /*!
782  * \brief store a bad input element preventing computation,
783  *        which may be a temporary one i.e. not residing the mesh,
784  *        then it will be deleted by InitComputeError()
785  */
786 //================================================================================
787
788 void SMESH_Algo::addBadInputElement(const SMDS_MeshElement* elem)
789 {
790   if ( elem )
791     _badInputElements.push_back( elem );
792 }
793
794 //=======================================================================
795 //function : addBadInputElements
796 //purpose  : store a bad input elements or nodes preventing computation
797 //=======================================================================
798
799 void SMESH_Algo::addBadInputElements(const SMESHDS_SubMesh* sm,
800                                      const bool             addNodes)
801 {
802   if ( sm )
803   {
804     if ( addNodes )
805     {
806       SMDS_NodeIteratorPtr nIt = sm->GetNodes();
807       while ( nIt->more() ) addBadInputElement( nIt->next() );
808     }
809     else
810     {
811       SMDS_ElemIteratorPtr eIt = sm->GetElements();
812       while ( eIt->more() ) addBadInputElement( eIt->next() );
813     }
814   }
815 }
816
817 //=============================================================================
818 /*!
819  *  
820  */
821 //=============================================================================
822
823 // int SMESH_Algo::NumberOfWires(const TopoDS_Shape& S)
824 // {
825 //   int i = 0;
826 //   for (TopExp_Explorer exp(S,TopAbs_WIRE); exp.More(); exp.Next())
827 //     i++;
828 //   return i;
829 // }
830
831 //=============================================================================
832 /*!
833  *  
834  */
835 //=============================================================================
836
837 int SMESH_Algo::NumberOfPoints(SMESH_Mesh& aMesh, const TopoDS_Wire& W)
838 {
839   int nbPoints = 0;
840   for (TopExp_Explorer exp(W,TopAbs_EDGE); exp.More(); exp.Next()) {
841     const TopoDS_Edge& E = TopoDS::Edge(exp.Current());
842     int nb = aMesh.GetSubMesh(E)->GetSubMeshDS()->NbNodes();
843     if(_quadraticMesh)
844       nb = nb/2;
845     nbPoints += nb + 1; // internal points plus 1 vertex of 2 (last point ?)
846   }
847   return nbPoints;
848 }
849
850