Salome HOME
SMESH_Hypothesis::Hypothesis_Status aStatus;
[modules/smesh.git] / src / StdMeshers / StdMeshers_AutomaticLength.cxx
1 //  Copyright (C) 2007-2008  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 //  SMESH SMESH : implementaion of SMESH idl descriptions
23 //  File   : StdMeshers_AutomaticLength.cxx
24 //  Author : Edward AGAPOV, OCC
25 //  Module : SMESH
26 //
27 #include "StdMeshers_AutomaticLength.hxx"
28
29 #include "SMESH_Mesh.hxx"
30 #include "SMESHDS_Mesh.hxx"
31 #include "SMESH_Algo.hxx"
32 #include "SMESHDS_SubMesh.hxx"
33
34 #include "utilities.h"
35
36 #include <TopTools_IndexedMapOfShape.hxx>
37 #include <TopExp.hxx>
38 #include <TopoDS.hxx>
39 #include <TopoDS_Edge.hxx>
40
41 using namespace std;
42
43 //=============================================================================
44 /*!
45  *  
46  */
47 //=============================================================================
48
49 StdMeshers_AutomaticLength::StdMeshers_AutomaticLength(int hypId, int studyId, SMESH_Gen * gen)
50   :SMESH_Hypothesis(hypId, studyId, gen)
51 {
52   _name = "AutomaticLength";
53   _param_algo_dim = 1; // is used by SMESH_Regular_1D
54
55   _mesh = 0;
56   _fineness = 0;
57 }
58
59 //=============================================================================
60 /*!
61  *  
62  */
63 //=============================================================================
64
65 StdMeshers_AutomaticLength::~StdMeshers_AutomaticLength()
66 {
67 }
68
69 //================================================================================
70 /*!
71  * \brief Set Fineness
72  * \param theFineness - The Fineness value [0.0-1.0],
73  *                        0 - coarse mesh
74  *                        1 - fine mesh
75  * 
76  * Raise if theFineness is out of range
77  * The "Initial Number of Elements on the Shortest Edge" (S0)
78  * is divided by (0.5 + 4.5 x theFineness)
79  */
80 //================================================================================
81
82 const double theCoarseConst = 0.5;
83 const double theFineConst   = 4.5;
84
85 void StdMeshers_AutomaticLength::SetFineness(double theFineness)
86   throw(SALOME_Exception)
87 {
88   if ( theFineness < 0.0 || theFineness > 1.0 )
89     throw SALOME_Exception(LOCALIZED("theFineness is out of range [0.0-1.0]"));
90
91   if ( _fineness != theFineness )
92   {
93     NotifySubMeshesHypothesisModification();
94     _fineness = theFineness;
95   }
96 }
97
98 namespace {
99
100   //================================================================================
101   /*!
102    * \brief Return pointer to TopoDS_TShape
103    * \param theShape - The TopoDS_Shape
104    * \retval inline const TopoDS_TShape* - result
105    */
106   //================================================================================
107
108   inline const TopoDS_TShape* getTShape(const TopoDS_Shape& theShape)
109   {
110     return theShape.TShape().operator->();
111   }
112
113   //================================================================================
114   /*!
115    * \brief computes segment length by S0 and edge length
116    */
117   //================================================================================
118
119   const double a14divPI = 14. / PI;
120
121   inline double segLength(double S0, double edgeLen, double minLen )
122   {
123     // PAL10237
124     // S = S0 * f(L/Lmin) where f(x) = 1 + (2/Pi * 7 * atan(x/5) )
125     // =>
126     // S = S0 * ( 1 + 14/PI * atan( L / ( 5 * Lmin )))
127     return S0 * ( 1. + a14divPI * atan( edgeLen / ( 5 * minLen )));
128   }
129
130   //================================================================================
131   /*!
132    * \brief Compute segment length for all edges
133    * \param theMesh - The mesh
134    * \param theTShapeToLengthMap - The map of edge to segment length
135    */
136   //================================================================================
137
138   void computeLengths( SMESHDS_Mesh*                       aMesh,
139                        map<const TopoDS_TShape*, double> & theTShapeToLengthMap,
140                        double &                            theS0,
141                        double &                            theMinLen)
142   {
143     theTShapeToLengthMap.clear();
144
145     TopoDS_Shape aMainShape = aMesh->ShapeToMesh();
146
147     // Find length of longest and shortest edge
148     double Lmin = DBL_MAX, Lmax = -DBL_MAX;
149     TopTools_IndexedMapOfShape edgeMap;
150     TopExp::MapShapes( aMainShape, TopAbs_EDGE, edgeMap);
151     for ( int i = 1; i <= edgeMap.Extent(); ++i )
152     {
153       TopoDS_Edge edge = TopoDS::Edge( edgeMap(i) );
154       //if ( BRep_Tool::Degenerated( edge )) continue;
155
156       Standard_Real L = SMESH_Algo::EdgeLength( edge );
157       if ( L < DBL_MIN ) continue;
158
159       if ( L > Lmax ) Lmax = L;
160       if ( L < Lmin ) Lmin = L;
161
162       // remember i-th edge length
163       theTShapeToLengthMap.insert( make_pair( getTShape( edge ), L ));
164     }
165
166     // Compute S0
167
168     // image attached to PAL10237
169
170     //   NbSeg
171     //     ^
172     //     |
173     //   10|\
174     //     | \
175     //     |  \
176     //     |   \
177     //    5|    --------
178     //     |
179     //     +------------>
180     //     1    10       Lmax/Lmin
181
182     const int NbSegMin = 5, NbSegMax = 10; //  on axis NbSeg
183     const double Lrat1 = 1., Lrat2 = 10.;  //  on axis Lmax/Lmin
184
185     double Lratio = Lmax/Lmin;
186     double NbSeg = NbSegMin;
187     if ( Lratio < Lrat2 )
188       NbSeg += ( Lrat2 - Lratio ) / ( Lrat2 - Lrat1 )  * ( NbSegMax - NbSegMin );
189
190     double S0 = Lmin / (int) NbSeg;
191     MESSAGE( "S0 = " << S0 << ", Lmin = " << Lmin << ", Nbseg = " << (int) NbSeg);
192
193     // Compute segments length for all edges
194     map<const TopoDS_TShape*, double>::iterator tshape_length = theTShapeToLengthMap.begin();
195     for ( ; tshape_length != theTShapeToLengthMap.end(); ++tshape_length )
196     {
197       double & L = tshape_length->second;
198       L = segLength( S0, L, Lmin );
199     }
200     theS0 = S0;
201     theMinLen = Lmin;
202   }
203 }
204
205 //=============================================================================
206 /*!
207  * \brief Computes segment length for an edge of given length
208  */
209 //=============================================================================
210
211 double StdMeshers_AutomaticLength::GetLength(const SMESH_Mesh* theMesh,
212                                              const double      theEdgeLength)
213   throw(SALOME_Exception)
214 {
215   if ( !theMesh ) throw SALOME_Exception(LOCALIZED("NULL Mesh"));
216
217   SMESHDS_Mesh* aMeshDS = const_cast< SMESH_Mesh* > ( theMesh )->GetMeshDS();
218   if ( theMesh != _mesh )
219   {
220     computeLengths( aMeshDS, _TShapeToLength, _S0, _minLen );
221     _mesh = theMesh;
222   }
223   double L = segLength( _S0, theEdgeLength, _minLen );
224   return L / (theCoarseConst + theFineConst * _fineness);
225 }
226
227 //=============================================================================
228 /*!
229  *  
230  */
231 //=============================================================================
232
233 double StdMeshers_AutomaticLength::GetLength(const SMESH_Mesh*   theMesh,
234                                              const TopoDS_Shape& anEdge)
235   throw(SALOME_Exception)
236 {
237   if ( !theMesh ) throw SALOME_Exception(LOCALIZED("NULL Mesh"));
238
239   if ( anEdge.IsNull() || anEdge.ShapeType() != TopAbs_EDGE )
240     throw SALOME_Exception(LOCALIZED("Bad edge shape"));
241
242   if ( theMesh != _mesh )
243   {
244     SMESHDS_Mesh* aMeshDS = const_cast< SMESH_Mesh* > ( theMesh )->GetMeshDS();
245     computeLengths( aMeshDS, _TShapeToLength, _S0, _minLen );
246     _mesh = theMesh;
247   }
248
249   map<const TopoDS_TShape*, double>::iterator tshape_length =
250     _TShapeToLength.find( getTShape( anEdge ));
251
252   if ( tshape_length == _TShapeToLength.end() )
253     return 1; // it is a dgenerated edge
254
255   return tshape_length->second / (theCoarseConst + theFineConst * _fineness);
256 }
257
258 //=============================================================================
259 /*!
260  *  
261  */
262 //=============================================================================
263
264 ostream & StdMeshers_AutomaticLength::SaveTo(ostream & save)
265 {
266   save << _fineness;
267   return save;
268 }
269
270 //=============================================================================
271 /*!
272  *  
273  */
274 //=============================================================================
275
276 istream & StdMeshers_AutomaticLength::LoadFrom(istream & load)
277 {
278   if ( ! ( load >> _fineness ))
279     load.clear(ios::badbit | load.rdstate());
280   return load;
281 }
282
283 //=============================================================================
284 /*!
285  *  
286  */
287 //=============================================================================
288
289 ostream & operator <<(ostream & save, StdMeshers_AutomaticLength & hyp)
290 {
291   return hyp.SaveTo( save );
292 }
293
294 //=============================================================================
295 /*!
296  *  
297  */
298 //=============================================================================
299
300 istream & operator >>(istream & load, StdMeshers_AutomaticLength & hyp)
301 {
302   return hyp.LoadFrom( load );
303 }
304
305 //================================================================================
306 /*!
307  * \brief Initialize Fineness by the mesh built on the geometry
308  * \param theMesh - the built mesh
309  * \param theShape - the geometry of interest
310  * \retval bool - true if parameter values have been successfully defined
311  */
312 //================================================================================
313
314 bool StdMeshers_AutomaticLength::SetParametersByMesh(const SMESH_Mesh*   theMesh,
315                                                      const TopoDS_Shape& theShape)
316 {
317   if ( !theMesh || theShape.IsNull() )
318     return false;
319
320   _fineness = 0;
321
322   SMESHDS_Mesh* aMeshDS = const_cast< SMESH_Mesh* >( theMesh )->GetMeshDS();
323
324   int nbEdges = 0;
325   TopTools_IndexedMapOfShape edgeMap;
326   TopExp::MapShapes( theShape, TopAbs_EDGE, edgeMap );
327   for ( int i = 1; i <= edgeMap.Extent(); ++i )
328   {
329     const TopoDS_Edge& edge = TopoDS::Edge( edgeMap( i ));
330
331     // assure the base automatic length is stored in _TShapeToLength
332     if ( i == 1 ) 
333       GetLength( theMesh, edge );
334
335     // get current segment length
336     double L = SMESH_Algo::EdgeLength( edge );
337     if ( L <= DBL_MIN )
338       continue;
339     SMESHDS_SubMesh * eSubMesh = aMeshDS->MeshElements( edge );
340     if ( !eSubMesh )
341       return false;
342     int nbSeg = eSubMesh->NbElements();
343     if ( nbSeg < 1 )
344       continue;
345     double segLen = L / nbSeg;
346
347     // get segment length from _TShapeToLength
348     map<const TopoDS_TShape*, double>::iterator tshape_length =
349       _TShapeToLength.find( getTShape( edge ));
350     if ( tshape_length == _TShapeToLength.end() )
351       continue;
352     double autoLen = tshape_length->second;
353
354     // segLen = autoLen / (theCoarseConst + theFineConst * _fineness) -->
355     _fineness += ( autoLen / segLen - theCoarseConst ) / theFineConst;
356
357     ++nbEdges;
358   }
359   if ( nbEdges )
360     _fineness /= nbEdges;
361
362   if (_fineness > 1.0)
363     _fineness = 1.0;
364   else if (_fineness < 0.0)
365     _fineness = 0.0;
366
367   return nbEdges;
368 }
369
370 //================================================================================
371 /*!
372  * \brief Initialize my parameter values by default parameters.
373  *  \retval bool - true if parameter values have been successfully defined
374  */
375 //================================================================================
376
377 bool StdMeshers_AutomaticLength::SetParametersByDefaults(const TDefaults&  /*theDflts*/,
378                                                          const SMESH_Mesh* /*theMesh*/)
379 {
380   return false;
381
382   // assure the base automatic length is stored in _TShapeToLength
383 //   GetLength( theMesh, elemLenght );
384
385 //   // find maximal edge length
386 //   double maxLen = 0;
387 //   map<const TopoDS_TShape*, double>::iterator
388 //     tshape_length = _TShapeToLength.begin(), slEnd = _TShapeToLength.end();
389 //   for ( ; tshape_length != slEnd; ++tshape_length )
390 //     if ( tshape_length->second > maxLen )
391 //       maxLen = tshape_length->second;
392
393 //   // automatic length for longest element
394 //   double autoLen = GetLength( theMesh, maxLen );
395
396 //   // elemLenght = autoLen / (theCoarseConst + theFineConst * _fineness) -->
397 //   _fineness = ( autoLen / elemLenght - theCoarseConst ) / theFineConst;
398
399 //   return true;
400 }
401
402