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