Salome HOME
0021336: EDF 1717 SMESH: New algorithm "body fitting" cartesian unstructured
[modules/smesh.git] / src / StdMeshers / StdMeshers_CartesianParameters3D.cxx
1 // Copyright (C) 2007-2011  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 //  File   : StdMeshers_CartesianParameters3D.cxx
24 //  Author : Edward AGAPOV
25 //  Module : SMESH
26 //
27 #include "StdMeshers_CartesianParameters3D.hxx"
28
29 #include "StdMeshers_NumberOfSegments.hxx"
30 #include "StdMeshers_Distribution.hxx"
31 #include "SMESH_Gen.hxx"
32
33 #include "utilities.h"
34
35 #include <Precision.hxx>
36 #include <Bnd_Box.hxx>
37
38 #include <limits>
39
40 using namespace std;
41
42 //=======================================================================
43 //function : StdMeshers_CartesianParameters3D
44 //purpose  : Constructor
45 //=======================================================================
46
47 StdMeshers_CartesianParameters3D::StdMeshers_CartesianParameters3D(int         hypId,
48                                                                    int         studyId,
49                                                                    SMESH_Gen * gen)
50   : SMESH_Hypothesis(hypId, studyId, gen),
51     _sizeThreshold( 4.0 ) // default according to the customer specification
52 {
53   _name = "CartesianParameters3D"; // used by "Cartesian_3D"
54   _param_algo_dim = 3; // 3D
55 }
56
57
58 namespace
59 {
60   const char* axisName[3] = { "X", "Y", "Z" };
61
62   //================================================================================
63   /*!
64    * \brief Checks validity of an axis index, throws in case of invalidity
65    */
66   //================================================================================
67
68   void checkAxis(const int axis)
69   {
70     if ( axis < 0 || axis > 2 )
71       throw SALOME_Exception(SMESH_Comment("Invalid axis index ") << axis <<
72                              ". Valid axis indices are 0, 1 and 2");
73   }
74
75   //================================================================================
76   /*!
77    * \brief Checks validity of spacing data, throws in case of invalidity
78    */
79   //================================================================================
80
81   void checkGridSpacing(std::vector<std::string>& spaceFunctions,
82                         std::vector<double>&      internalPoints,
83                         const std::string&        axis)
84     throw ( SALOME_Exception )
85   {
86     if ( spaceFunctions.empty() )
87       throw SALOME_Exception(SMESH_Comment("Empty space function for ") << axis );
88
89     for ( size_t i = 1; i < internalPoints.size(); ++i )
90       if ( internalPoints[i] - internalPoints[i-1] < 0 )
91         throw SALOME_Exception(SMESH_Comment("Wrong order of internal points along ") << axis);
92       else if ( internalPoints[i] - internalPoints[i-1] < 1e-3 )
93         throw SALOME_Exception(SMESH_Comment("Too close internal points along ") << axis );
94
95     const double tol = Precision::Confusion();
96     if ( !internalPoints.empty() &&
97          ( internalPoints.front() < -tol || internalPoints.back() > 1 + tol ))
98       throw SALOME_Exception(SMESH_Comment("Invalid internal points along ") << axis);
99
100     if ( internalPoints.empty() || internalPoints.front() > tol )
101       internalPoints.insert( internalPoints.begin(), 0. );
102     if ( internalPoints.size() < 2 || internalPoints.back() < 1 - tol )
103       internalPoints.push_back( 1. );
104
105     if ( internalPoints.size() != spaceFunctions.size() + 1 )
106       throw SALOME_Exception
107         (SMESH_Comment("Numbre of internal points mismatch number of functions for ") << axis);
108
109     for ( size_t i = 0; i < spaceFunctions.size(); ++i )
110       spaceFunctions[i] =
111         StdMeshers_NumberOfSegments::CheckExpressionFunction( spaceFunctions[i], -1 );
112   }
113 }
114
115 //=======================================================================
116 //function : SetGrid
117 //purpose  : Sets coordinates of node positions along an axes
118 //=======================================================================
119
120 void StdMeshers_CartesianParameters3D::SetGrid(std::vector<double>& coords, int axis)
121   throw ( SALOME_Exception )
122 {
123   checkAxis( axis );
124
125   if ( coords.size() < 2 )
126     throw SALOME_Exception(LOCALIZED("Wrong number of grid coordinates"));
127
128   std::sort( coords.begin(), coords.end() );
129
130   bool changed = ( _coords[axis] != coords );
131   if ( changed )
132   {
133     _coords[axis] = coords;
134     NotifySubMeshesHypothesisModification();
135   }
136
137   _spaceFunctions[axis].clear();
138   _internalPoints[axis].clear();
139 }
140
141 //=======================================================================
142 //function : SetGridSpacing
143 //purpose  : Set grid spacing along the three axes
144 //=======================================================================
145
146 void StdMeshers_CartesianParameters3D::SetGridSpacing(std::vector<string>& xSpaceFuns,
147                                                       std::vector<double>& xInternalPoints,
148                                                       const int            axis)
149   throw ( SALOME_Exception )
150 {
151   checkAxis( axis );
152
153   checkGridSpacing( xSpaceFuns, xInternalPoints, axisName[axis] );
154
155   bool changed = ( xSpaceFuns      != _spaceFunctions[axis] ||
156                    xInternalPoints != _internalPoints[axis] );
157
158   _spaceFunctions[axis] = xSpaceFuns;
159   _internalPoints[axis] = xInternalPoints;
160   _coords[axis].clear();
161
162   if ( changed )
163     NotifySubMeshesHypothesisModification();
164 }
165
166 //=======================================================================
167 //function : SetSizeThreshold
168 //purpose  : Set size threshold
169 //=======================================================================
170
171 void StdMeshers_CartesianParameters3D::SetSizeThreshold(const double threshold)
172   throw ( SALOME_Exception )
173 {
174   if ( threshold <= 1.0 )
175     throw SALOME_Exception(LOCALIZED("threshold must be > 1.0"));
176
177   bool changed = fabs( _sizeThreshold - threshold ) > 1e-6;
178   _sizeThreshold = threshold;
179
180   if ( changed )
181     NotifySubMeshesHypothesisModification();
182 }
183
184 //=======================================================================
185 //function : GetGridSpacing
186 //purpose  : return spacing
187 //=======================================================================
188
189 void StdMeshers_CartesianParameters3D::GetGridSpacing(std::vector<std::string>& spaceFunctions,
190                                                       std::vector<double>&      internalPoints,
191                                                       const int                 axis) const
192   throw ( SALOME_Exception )
193 {
194   if ( !IsGridBySpacing(axis) )
195     throw SALOME_Exception(LOCALIZED("The grid is defined by coordinates and not by spacing"));
196
197   spaceFunctions = _spaceFunctions[axis];
198   internalPoints = _internalPoints[axis];
199 }
200
201 //=======================================================================
202 //function : IsGridBySpacing
203 //=======================================================================
204
205 bool StdMeshers_CartesianParameters3D::IsGridBySpacing(const int axis) const
206   throw ( SALOME_Exception )
207 {
208   checkAxis(axis);
209   return !_spaceFunctions[axis].empty();
210 }
211
212
213 //=======================================================================
214 //function : ComputeCoordinates
215 //purpose  : Computes node coordinates by spacing functions
216 //=======================================================================
217
218 void StdMeshers_CartesianParameters3D::ComputeCoordinates(const double         x0,
219                                                           const double         x1,
220                                                           vector<std::string>& spaceFuns,
221                                                           vector<double>&      points,
222                                                           vector<double>&      coords,
223                                                           const std::string&   axis )
224   throw ( SALOME_Exception )
225 {
226   checkGridSpacing( spaceFuns, points, axis );
227
228   coords.clear();
229   for ( size_t i = 0; i < spaceFuns.size(); ++i )
230   {
231     FunctionExpr fun( spaceFuns[i].c_str(), /*convMode=*/-1 );
232
233     const double p0 = x0 * ( 1. - points[i])   + x1 * points[i];
234     const double p1 = x0 * ( 1. - points[i+1]) + x1 * points[i+1];
235     const double length = p1 - p0;
236
237     const size_t nbSections = 1000;
238     const double sectionLen = ( p1 - p0 ) / nbSections;
239     vector< double > nbSegments( nbSections + 1 );
240     nbSegments[ 0 ] = 0.;
241
242     double t, spacing = 0;
243     for ( size_t i = 1; i <= nbSections; ++i )
244     {
245       t = double( i ) / nbSections;
246       if ( !fun.value( t, spacing ) || spacing < std::numeric_limits<double>::min() )
247         throw SALOME_Exception(LOCALIZED("Invalid spacing function"));
248       nbSegments[ i ] = nbSegments[ i-1 ] + std::min( 1., sectionLen / spacing );
249     }
250
251     const int nbCells = max (1, int(floor(nbSegments.back()+0.5)));
252     const double corr = nbCells / nbSegments.back();
253
254     if ( coords.empty() ) coords.push_back( p0 );
255
256     for ( size_t iCell = 1, i = 1; i <= nbSections; ++i )
257     {
258       if ( nbSegments[i]*corr >= iCell )
259       {
260         t = (i - ( nbSegments[i] - iCell/corr )/( nbSegments[i] - nbSegments[i-1] )) / nbSections;
261         coords.push_back( p0 + t * length );
262         ++iCell;
263       }
264     }
265     const double lastCellLen = coords.back() - coords[ coords.size() - 2 ];
266     if ( fabs( coords.back() - p1 ) > 0.5 * lastCellLen )
267       coords.push_back ( p1 );
268   }
269 }
270
271 //=======================================================================
272 //function : GetCoordinates
273 //purpose  : Return coordinates of node positions along the three axes.
274 //           If the grid is defined by spacing functions, the coordinates are computed
275 //=======================================================================
276
277 void StdMeshers_CartesianParameters3D::GetCoordinates(std::vector<double>& xNodes,
278                                                       std::vector<double>& yNodes,
279                                                       std::vector<double>& zNodes,
280                                                       const Bnd_Box&       bndBox) const
281   throw ( SALOME_Exception )
282 {
283   double x0,y0,z0, x1,y1,z1;
284   if ( IsGridBySpacing(0) || IsGridBySpacing(1) || IsGridBySpacing(2))
285   {
286     if ( bndBox.IsVoid() ||
287          bndBox.IsXThin( Precision::Confusion() ) ||
288          bndBox.IsYThin( Precision::Confusion() ) ||
289          bndBox.IsZThin( Precision::Confusion() ) )
290       throw SALOME_Exception(LOCALIZED("Invalid bounding box"));
291     bndBox.Get(x0,y0,z0, x1,y1,z1);
292   }
293
294   StdMeshers_CartesianParameters3D* me = const_cast<StdMeshers_CartesianParameters3D*>(this);
295   if ( IsGridBySpacing(0) )
296     ComputeCoordinates( x0, x1, me->_spaceFunctions[0], me->_internalPoints[0], xNodes, "X" );
297   else
298     xNodes = _coords[0];
299
300   if ( IsGridBySpacing(1) )
301     ComputeCoordinates( y0, y1, me->_spaceFunctions[1], me->_internalPoints[1], yNodes, "Y" );
302   else
303     yNodes = _coords[1];
304
305   if ( IsGridBySpacing(2) )
306     ComputeCoordinates( z0, z1, me->_spaceFunctions[2], me->_internalPoints[2], zNodes, "Z" );
307   else
308     zNodes = _coords[2];
309 }
310
311 //=======================================================================
312 //function : GetGrid
313 //purpose  : Return coordinates of node positions along the three axes
314 //=======================================================================
315
316 void StdMeshers_CartesianParameters3D::GetGrid(std::vector<double>& coords, int axis) const
317   throw ( SALOME_Exception )
318 {
319   if ( IsGridBySpacing(axis) )
320     throw SALOME_Exception(LOCALIZED("The grid is defined by spacing and not by coordinates"));
321
322   coords = _coords[axis];
323 }
324
325 //=======================================================================
326 //function : GetSizeThreshold
327 //purpose  : Return size threshold
328 //=======================================================================
329
330 double StdMeshers_CartesianParameters3D::GetSizeThreshold() const
331 {
332   return _sizeThreshold;
333 }
334
335 //=======================================================================
336 //function : IsDefined
337 //purpose  : Return true if parameters are well defined
338 //=======================================================================
339
340 bool StdMeshers_CartesianParameters3D::IsDefined() const
341 {
342   for ( int i = 0; i < 3; ++i )
343     if (_coords[i].empty() && (_spaceFunctions[i].empty() || _internalPoints[i].empty()))
344       return false;
345
346   return ( _sizeThreshold > 1.0 );
347 }
348
349 //=======================================================================
350 //function : SaveTo
351 //purpose  : store my parameters into a stream
352 //=======================================================================
353
354 std::ostream & StdMeshers_CartesianParameters3D::SaveTo(std::ostream & save)
355 {
356   save << _sizeThreshold << " ";
357
358   for ( int i = 0; i < 3; ++i )
359   {
360     save << _coords[i].size() << " ";
361     for ( size_t j = 0; j < _coords[i].size(); ++j )
362       save << _coords[i][j] << " ";
363
364     save << _internalPoints[i].size() << " ";
365     for ( size_t j = 0; j < _internalPoints[i].size(); ++j )
366       save << _internalPoints[i][j] << " ";
367
368     save << _spaceFunctions[i].size() << " ";
369     for ( size_t j = 0; j < _spaceFunctions[i].size(); ++j )
370       save << _spaceFunctions[i][j] << " ";
371   }
372
373   return save;
374 }
375
376 //=======================================================================
377 //function : LoadFrom
378 //purpose  : resore my parameters from a stream
379 //=======================================================================
380
381 std::istream & StdMeshers_CartesianParameters3D::LoadFrom(std::istream & load)
382 {
383   bool ok;
384
385   ok = (load >> _sizeThreshold  );
386   for ( int ax = 0; ax < 3; ++ax )
387   {
388     if (ok)
389     {
390       size_t i = 0;
391       ok = (load >> i  );
392       if ( i > 0 && ok )
393       {
394         _coords[ax].resize( i );
395         for ( i = 0; i < _coords[ax].size() && ok; ++i )
396           ok = (load >> _coords[ax][i]  );
397       }
398     }
399     if (ok)
400     {
401       size_t i = 0;
402       ok = (load >> i  );
403       if ( i > 0 && ok )
404       {
405         _internalPoints[ax].resize( i );
406         for ( i = 0; i < _internalPoints[ax].size() && ok; ++i )
407           ok = (load >> _internalPoints[ax][i]  );
408       }
409     }
410     if (ok)
411     {
412       size_t i = 0;
413       ok = (load >> i  );
414       if ( i > 0 && ok )
415       {
416         _spaceFunctions[ax].resize( i );
417         for ( i = 0; i < _spaceFunctions[ax].size() && ok; ++i )
418           ok = (load >> _spaceFunctions[ax][i]  );
419       }
420     }
421   }
422   return load;
423 }
424
425 //=======================================================================
426 //function : SetParametersByMesh
427 //=======================================================================
428
429 bool StdMeshers_CartesianParameters3D::SetParametersByMesh(const SMESH_Mesh*   ,
430                                                            const TopoDS_Shape& )
431 {
432   return false;
433 }
434
435 //=======================================================================
436 //function : SetParametersByDefaults
437 //=======================================================================
438
439 bool StdMeshers_CartesianParameters3D::SetParametersByDefaults(const TDefaults&  dflts,
440                                                                const SMESH_Mesh* /*theMesh*/)
441 {
442   if ( dflts._elemLength > 1e-100 )
443   {
444     vector<string> spacing( 1, SMESH_Comment(dflts._elemLength));
445     vector<double> intPnts;
446     SetGridSpacing( spacing, intPnts, 0 );
447     SetGridSpacing( spacing, intPnts, 1 );
448     SetGridSpacing( spacing, intPnts, 2 );
449     return true;
450   }
451   return false;
452 }
453