Salome HOME
Merge from OCC_development_generic_2006
[modules/smesh.git] / src / SMESH / SMESH_Algo.cxx
1 //  SMESH SMESH : implementaion of SMESH idl descriptions
2 //
3 //  Copyright (C) 2003  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.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org 
21 //
22 //
23 //
24 //  File   : SMESH_Algo.cxx
25 //  Author : Paul RASCLE, EDF
26 //  Module : SMESH
27 //  $Header$
28
29 using namespace std;
30 #include "SMESH_Algo.hxx"
31 #include "SMESH_Gen.hxx"
32 #include "SMESH_Mesh.hxx"
33 #include "SMESH_HypoFilter.hxx"
34 #include "SMDS_FacePosition.hxx"
35 #include "SMDS_EdgePosition.hxx"
36 #include "SMDS_MeshElement.hxx"
37 #include "SMDS_MeshNode.hxx"
38 #include "SMESHDS_Mesh.hxx"
39 #include "SMESHDS_SubMesh.hxx"
40
41 #include <BRep_Tool.hxx>
42 #include <GCPnts_AbscissaPoint.hxx>
43 #include <GeomAdaptor_Curve.hxx>
44 #include <Geom_Surface.hxx>
45 #include <TopLoc_Location.hxx>
46 #include <TopTools_ListIteratorOfListOfShape.hxx>
47 #include <TopTools_ListOfShape.hxx>
48 #include <TopoDS.hxx>
49 #include <TopoDS_Face.hxx>
50 #include <gp_Pnt.hxx>
51 #include <gp_Pnt2d.hxx>
52 #include <gp_Vec.hxx>
53
54 #include "utilities.h"
55
56 #include <algorithm>
57
58 //=============================================================================
59 /*!
60  *  
61  */
62 //=============================================================================
63
64 SMESH_Algo::SMESH_Algo(int hypId, int studyId,
65         SMESH_Gen * gen):SMESH_Hypothesis(hypId, studyId, gen)
66 {
67 //   _compatibleHypothesis.push_back("hypothese_bidon");
68         _type = ALGO;
69         gen->_mapAlgo[hypId] = this;
70
71         _onlyUnaryInput = _requireDescretBoundary = true;
72 }
73
74 //=============================================================================
75 /*!
76  *  
77  */
78 //=============================================================================
79
80 SMESH_Algo::~SMESH_Algo()
81 {
82 }
83
84 //=============================================================================
85 /*!
86  *  
87  */
88 //=============================================================================
89
90 const vector < string > &SMESH_Algo::GetCompatibleHypothesis()
91 {
92         return _compatibleHypothesis;
93 }
94
95 //=============================================================================
96 /*!
97  *  List the hypothesis used by the algorithm associated to the shape.
98  *  Hypothesis associated to father shape -are- taken into account (see
99  *  GetAppliedHypothesis). Relevant hypothesis have a name (type) listed in
100  *  the algorithm. This method could be surcharged by specific algorithms, in 
101  *  case of several hypothesis simultaneously applicable.
102  */
103 //=============================================================================
104
105 const list <const SMESHDS_Hypothesis *> & SMESH_Algo::GetUsedHypothesis(
106         SMESH_Mesh & aMesh, const TopoDS_Shape & aShape)
107 {
108   _usedHypList.clear();
109   if ( !_compatibleHypothesis.empty() )
110   {
111     SMESH_HypoFilter filter( SMESH_HypoFilter::HasName( _compatibleHypothesis[0] ));
112     for ( int i = 1; i < _compatibleHypothesis.size(); ++i )
113       filter.Or( filter.HasName( _compatibleHypothesis[ i ] ));
114
115     aMesh.GetHypotheses( aShape, filter, _usedHypList, true );
116     if ( _usedHypList.size() > 1 )
117       _usedHypList.clear();     //only one compatible hypothesis allowed
118   }
119   return _usedHypList;
120 }
121
122 //=============================================================================
123 /*!
124  *  List the relevant hypothesis associated to the shape. Relevant hypothesis
125  *  have a name (type) listed in the algorithm. Hypothesis associated to
126  *  father shape -are not- taken into account (see GetUsedHypothesis)
127  */
128 //=============================================================================
129
130 const list<const SMESHDS_Hypothesis *> & SMESH_Algo::GetAppliedHypothesis(
131         SMESH_Mesh & aMesh, const TopoDS_Shape & aShape)
132 {
133   _appliedHypList.clear();
134   if ( !_compatibleHypothesis.empty() )
135   {
136     SMESH_HypoFilter filter( SMESH_HypoFilter::HasName( _compatibleHypothesis[0] ));
137     for ( int i = 1; i < _compatibleHypothesis.size(); ++i )
138       filter.Or( filter.HasName( _compatibleHypothesis[ i ] ));
139     
140     aMesh.GetHypotheses( aShape, filter, _appliedHypList, false );
141   }
142   return _appliedHypList;
143 }
144
145 //=============================================================================
146 /*!
147  *  Compute length of an edge
148  */
149 //=============================================================================
150
151 double SMESH_Algo::EdgeLength(const TopoDS_Edge & E)
152 {
153   double UMin = 0, UMax = 0;
154   if (BRep_Tool::Degenerated(E))
155     return 0;
156   TopLoc_Location L;
157   Handle(Geom_Curve) C = BRep_Tool::Curve(E, L, UMin, UMax);
158   GeomAdaptor_Curve AdaptCurve(C);
159   GCPnts_AbscissaPoint gabs;
160   double length = gabs.Length(AdaptCurve, UMin, UMax);
161   return length;
162 }
163
164 //================================================================================
165 /*!
166  * \brief Find out elements orientation on a geometrical face
167  * \param theFace - The face correctly oriented in the shape being meshed
168  * \param theMeshDS - The mesh data structure
169  * \retval bool - true if the face normal and the normal of first element
170  *                in the correspoding submesh point in different directions
171  */
172 //================================================================================
173
174 bool SMESH_Algo::IsReversedSubMesh (const TopoDS_Face&  theFace,
175                                     SMESHDS_Mesh*       theMeshDS)
176 {
177   if ( theFace.IsNull() || !theMeshDS )
178     return false;
179
180   // find out orientation of a meshed face
181   int faceID = theMeshDS->ShapeToIndex( theFace );
182   TopoDS_Shape aMeshedFace = theMeshDS->IndexToShape( faceID );
183   bool isReversed = ( theFace.Orientation() != aMeshedFace.Orientation() );
184
185   const SMESHDS_SubMesh * aSubMeshDSFace = theMeshDS->MeshElements( faceID );
186   if ( !aSubMeshDSFace )
187     return isReversed;
188
189   // find element with node located on face and get its normal
190   const SMDS_FacePosition* facePos = 0;
191   int vertexID = 0;
192   gp_Pnt nPnt[3];
193   gp_Vec Ne;
194   bool normalOK = false;
195   SMDS_ElemIteratorPtr iteratorElem = aSubMeshDSFace->GetElements();
196   while ( iteratorElem->more() ) // loop on elements on theFace
197   {
198     const SMDS_MeshElement* elem = iteratorElem->next();
199     if ( elem && elem->NbNodes() > 2 ) {
200       SMDS_ElemIteratorPtr nodesIt = elem->nodesIterator();
201       const SMDS_FacePosition* fPos = 0;
202       int i = 0, vID = 0;
203       while ( nodesIt->more() ) { // loop on nodes
204         const SMDS_MeshNode* node
205           = static_cast<const SMDS_MeshNode *>(nodesIt->next());
206         if ( i == 3 ) i = 2;
207         nPnt[ i++ ].SetCoord( node->X(), node->Y(), node->Z() );
208         // check position
209         const SMDS_PositionPtr& pos = node->GetPosition();
210         if ( !pos ) continue;
211         if ( pos->GetTypeOfPosition() == SMDS_TOP_FACE ) {
212           fPos = dynamic_cast< const SMDS_FacePosition* >( pos.get() );
213         }
214         else if ( pos->GetTypeOfPosition() == SMDS_TOP_VERTEX ) {
215           vID = pos->GetShapeId();
216         }
217       }
218       if ( fPos || ( !normalOK && vID )) {
219         // compute normal
220         gp_Vec v01( nPnt[0], nPnt[1] ), v02( nPnt[0], nPnt[2] );
221         if ( v01.SquareMagnitude() > RealSmall() &&
222              v02.SquareMagnitude() > RealSmall() )
223         {
224           Ne = v01 ^ v02;
225           normalOK = ( Ne.SquareMagnitude() > RealSmall() );
226         }
227         // we need position on theFace or at least on vertex
228         if ( normalOK ) {
229           vertexID = vID;
230           if ((facePos = fPos))
231             break;
232         }
233       }
234     }
235   }
236   if ( !normalOK )
237     return isReversed;
238
239   // node position on face
240   double u,v;
241   if ( facePos ) {
242     u = facePos->GetUParameter();
243     v = facePos->GetVParameter();
244   }
245   else if ( vertexID ) {
246     TopoDS_Shape V = theMeshDS->IndexToShape( vertexID );
247     if ( V.IsNull() || V.ShapeType() != TopAbs_VERTEX )
248       return isReversed;
249     gp_Pnt2d uv = BRep_Tool::Parameters( TopoDS::Vertex( V ), theFace );
250     u = uv.X();
251     v = uv.Y();
252   }
253   else
254   {
255     return isReversed;
256   }
257
258   // face normal at node position
259   TopLoc_Location loc;
260   Handle(Geom_Surface) surf = BRep_Tool::Surface( theFace, loc );
261   if ( surf.IsNull() || surf->Continuity() < GeomAbs_C1 ) return isReversed;
262   gp_Vec d1u, d1v;
263   surf->D1( u, v, nPnt[0], d1u, d1v );
264   gp_Vec Nf = (d1u ^ d1v).Transformed( loc );
265
266   if ( theFace.Orientation() == TopAbs_REVERSED )
267     Nf.Reverse();
268
269   return Ne * Nf < 0.;
270 }
271
272 //================================================================================
273 /*!
274  * \brief Initialize my parameter values by the mesh built on the geometry
275  * \param theMesh - the built mesh
276  * \param theShape - the geometry of interest
277  * \retval bool - true if parameter values have been successfully defined
278  *
279  * Just return false as the algorithm does not hold parameters values
280  */
281 //================================================================================
282
283 bool SMESH_Algo::SetParametersByMesh(const SMESH_Mesh* /*theMesh*/,
284                                      const TopoDS_Shape& /*theShape*/)
285 {
286   return false;
287 }
288
289 //================================================================================
290 /*!
291  * \brief Fill vector of node parameters on geometrical edge, including vertex nodes
292  * \param theMesh - The mesh containing nodes
293  * \param theEdge - The geometrical edge of interest
294  * \param theParams - The resulting vector of sorted node parameters
295  * \retval bool - false if not all parameters are OK
296  */
297 //================================================================================
298
299 bool SMESH_Algo::GetNodeParamOnEdge(const SMESHDS_Mesh* theMesh,
300                                     const TopoDS_Edge&  theEdge,
301                                     vector< double > &  theParams)
302 {
303   theParams.clear();
304
305   if ( !theMesh || theEdge.IsNull() )
306     return false;
307
308   SMESHDS_SubMesh * eSubMesh = theMesh->MeshElements( theEdge );
309   if ( !eSubMesh || !eSubMesh->GetElements()->more() )
310     return false; // edge is not meshed
311
312   int nbEdgeNodes = 0;
313   set < double > paramSet;
314   if ( eSubMesh )
315   {
316     // loop on nodes of an edge: sort them by param on edge
317     SMDS_NodeIteratorPtr nIt = eSubMesh->GetNodes();
318     while ( nIt->more() )
319     {
320       const SMDS_MeshNode* node = nIt->next();
321       const SMDS_PositionPtr& pos = node->GetPosition();
322       if ( pos->GetTypeOfPosition() != SMDS_TOP_EDGE )
323         return false;
324       const SMDS_EdgePosition* epos =
325         static_cast<const SMDS_EdgePosition*>(node->GetPosition().get());
326       paramSet.insert( epos->GetUParameter() );
327       ++nbEdgeNodes;
328     }
329   }
330   // add vertex nodes params
331   Standard_Real f, l;
332   BRep_Tool::Range(theEdge, f, l);
333   paramSet.insert( f );
334   paramSet.insert( l );
335   if ( paramSet.size() != nbEdgeNodes + 2 )
336     return false; // there are equal parameters
337
338   // fill the vector
339   theParams.resize( paramSet.size() );
340   set < double >::iterator   par    = paramSet.begin();
341   vector< double >::iterator vecPar = theParams.begin();
342   for ( ; par != paramSet.end(); ++par, ++vecPar )
343     *vecPar = *par;
344
345   return theParams.size() > 1;
346 }