Salome HOME
Merge with OCC_development_01
[modules/smesh.git] / src / StdMeshers / StdMeshers_Regular_1D.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   : StdMeshers_Regular_1D.cxx
25 //           Moved here from SMESH_Regular_1D.cxx
26 //  Author : Paul RASCLE, EDF
27 //  Module : SMESH
28 //  $Header$
29
30 using namespace std;
31
32 #include "StdMeshers_Regular_1D.hxx"
33 #include "SMESH_Gen.hxx"
34 #include "SMESH_Mesh.hxx"
35
36 #include "StdMeshers_LocalLength.hxx"
37 #include "StdMeshers_NumberOfSegments.hxx"
38 #include "StdMeshers_Arithmetic1D.hxx"
39 #include "StdMeshers_StartEndLength.hxx"
40 #include "StdMeshers_Deflection1D.hxx"
41
42 #include "SMDS_MeshElement.hxx"
43 #include "SMDS_MeshNode.hxx"
44 #include "SMDS_EdgePosition.hxx"
45 #include "SMESH_subMesh.hxx"
46
47 #include "utilities.h"
48
49 #include <BRep_Tool.hxx>
50 #include <TopoDS_Edge.hxx>
51 #include <TopoDS_Shape.hxx>
52 #include <TopTools_ListIteratorOfListOfShape.hxx>
53 #include <GeomAdaptor_Curve.hxx>
54 #include <GCPnts_AbscissaPoint.hxx>
55 #include <GCPnts_UniformAbscissa.hxx>
56 #include <GCPnts_UniformDeflection.hxx>
57 #include <Standard_ErrorHandler.hxx>
58 #include <Precision.hxx>
59
60 #include <string>
61 //#include <algorithm>
62
63 //=============================================================================
64 /*!
65  *  
66  */
67 //=============================================================================
68
69 StdMeshers_Regular_1D::StdMeshers_Regular_1D(int hypId, int studyId,
70         SMESH_Gen * gen):SMESH_1D_Algo(hypId, studyId, gen)
71 {
72         MESSAGE("StdMeshers_Regular_1D::StdMeshers_Regular_1D");
73         _name = "Regular_1D";
74         _shapeType = (1 << TopAbs_EDGE);
75
76         _compatibleHypothesis.push_back("LocalLength");
77         _compatibleHypothesis.push_back("NumberOfSegments");
78         _compatibleHypothesis.push_back("StartEndLength");
79         _compatibleHypothesis.push_back("Deflection1D");
80         _compatibleHypothesis.push_back("Arithmetic1D");
81 }
82
83 //=============================================================================
84 /*!
85  *  
86  */
87 //=============================================================================
88
89 StdMeshers_Regular_1D::~StdMeshers_Regular_1D()
90 {
91 }
92
93 //=============================================================================
94 /*!
95  *  
96  */
97 //=============================================================================
98
99 bool StdMeshers_Regular_1D::CheckHypothesis
100                          (SMESH_Mesh& aMesh,
101                           const TopoDS_Shape& aShape,
102                           SMESH_Hypothesis::Hypothesis_Status& aStatus)
103 {
104   _hypType = NONE;
105
106   const list <const SMESHDS_Hypothesis * >&hyps = GetUsedHypothesis(aMesh, aShape);
107   if (hyps.size() == 0)
108   {
109     aStatus = SMESH_Hypothesis::HYP_MISSING;
110     return false;  // can't work without a hypothesis
111   }
112
113   // use only the first hypothesis
114   const SMESHDS_Hypothesis *theHyp = hyps.front();
115
116   string hypName = theHyp->GetName();
117
118   if (hypName == "LocalLength")
119   {
120     const StdMeshers_LocalLength * hyp =
121       dynamic_cast <const StdMeshers_LocalLength * >(theHyp);
122     ASSERT(hyp);
123     _value[ BEG_LENGTH_IND ] = _value[ END_LENGTH_IND ] = hyp->GetLength();
124     ASSERT( _value[ BEG_LENGTH_IND ] > 0 );
125     _hypType = LOCAL_LENGTH;
126     aStatus = SMESH_Hypothesis::HYP_OK;
127   }
128
129   else if (hypName == "NumberOfSegments")
130   {
131     const StdMeshers_NumberOfSegments * hyp =
132       dynamic_cast <const StdMeshers_NumberOfSegments * >(theHyp);
133     ASSERT(hyp);
134     _value[ NB_SEGMENTS_IND  ] = hyp->GetNumberOfSegments();
135     _value[ SCALE_FACTOR_IND ] = hyp->GetScaleFactor();
136     ASSERT( _value[ NB_SEGMENTS_IND ] > 0 );
137     _hypType = NB_SEGMENTS;
138     aStatus = SMESH_Hypothesis::HYP_OK;
139   }
140
141   else if (hypName == "Arithmetic1D")
142   {
143     const StdMeshers_Arithmetic1D * hyp =
144       dynamic_cast <const StdMeshers_Arithmetic1D * >(theHyp);
145     ASSERT(hyp);
146     _value[ BEG_LENGTH_IND ] = hyp->GetLength( true );
147     _value[ END_LENGTH_IND ] = hyp->GetLength( false );
148     ASSERT( _value[ BEG_LENGTH_IND ] > 0 && _value[ END_LENGTH_IND ] > 0 );
149     _hypType = ARITHMETIC_1D;
150     aStatus = SMESH_Hypothesis::HYP_OK;
151   }
152
153   else if (hypName == "StartEndLength")
154   {
155     const StdMeshers_StartEndLength * hyp =
156       dynamic_cast <const StdMeshers_StartEndLength * >(theHyp);
157     ASSERT(hyp);
158     _value[ BEG_LENGTH_IND ] = hyp->GetLength( true );
159     _value[ END_LENGTH_IND ] = hyp->GetLength( false );
160     ASSERT( _value[ BEG_LENGTH_IND ] > 0 && _value[ END_LENGTH_IND ] > 0 );
161     _hypType = BEG_END_LENGTH;
162     aStatus = SMESH_Hypothesis::HYP_OK;
163   }
164
165   else if (hypName == "Deflection1D")
166   {
167     const StdMeshers_Deflection1D * hyp =
168       dynamic_cast <const StdMeshers_Deflection1D * >(theHyp);
169     ASSERT(hyp);
170     _value[ DEFLECTION_IND ] = hyp->GetDeflection();
171     ASSERT( _value[ DEFLECTION_IND ] > 0 );
172     _hypType = DEFLECTION;
173     aStatus = SMESH_Hypothesis::HYP_OK;
174   }
175   else
176     aStatus = SMESH_Hypothesis::HYP_INCOMPATIBLE;
177
178   return ( _hypType != NONE );
179 }
180
181 //=============================================================================
182 /*!
183  *  
184  */
185 //=============================================================================
186 bool StdMeshers_Regular_1D::computeInternalParameters(const TopoDS_Edge& theEdge,
187                                                       list<double> &     theParams) const
188 {
189   theParams.clear();
190
191   double f, l;
192   Handle(Geom_Curve) Curve = BRep_Tool::Curve(theEdge, f, l);
193   GeomAdaptor_Curve C3d(Curve);
194
195   double length = EdgeLength(theEdge);
196   //SCRUTE(length);
197
198   switch( _hypType )
199   {
200   case LOCAL_LENGTH:
201   case NB_SEGMENTS: {
202
203     double eltSize = 1;
204     if ( _hypType == LOCAL_LENGTH )
205     {
206       double nbseg = ceil(length / _value[ BEG_LENGTH_IND ]); // integer sup
207       if (nbseg <= 0)
208         nbseg = 1;                        // degenerated edge
209       eltSize = length / nbseg;
210     }
211     else
212     {
213       double epsilon = 0.001;
214       if (fabs(_value[ SCALE_FACTOR_IND ] - 1.0) > epsilon)
215       {
216         double alpha =
217           pow( _value[ SCALE_FACTOR_IND ], 1.0 / (_value[ NB_SEGMENTS_IND ] - 1));
218         double factor =
219           length / (1 - pow( alpha,_value[ NB_SEGMENTS_IND ]));
220
221         int i, NbPoints = 1 + (int) _value[ NB_SEGMENTS_IND ];
222         for ( i = 2; i < NbPoints; i++ )
223         {
224           double param = factor * (1 - pow(alpha, i - 1));
225           theParams.push_back( param );
226         }
227         return true;
228       }
229       else
230       {
231         eltSize = length / _value[ NB_SEGMENTS_IND ];
232       }
233     }
234
235     GCPnts_UniformAbscissa Discret(C3d, eltSize, f, l);
236     if ( !Discret.IsDone() )
237       return false;
238
239     int NbPoints = Discret.NbPoints();
240     for ( int i = 2; i < NbPoints; i++ )
241     {
242       double param = Discret.Parameter(i);
243       theParams.push_back( param );
244     }
245     return true;
246   }
247
248   case BEG_END_LENGTH: {
249
250     // geometric progression: SUM(n) = ( a1 - an * q ) / ( 1 - q ) = length
251
252     double a1 = _value[ BEG_LENGTH_IND ];
253     double an = _value[ END_LENGTH_IND ];
254     double q  = ( length - a1 ) / ( length - an );
255
256     double U1 = Min ( f, l );
257     double Un = Max ( f, l );
258     double param = U1;
259     double eltSize = a1;
260     while ( 1 ) {
261       // computes a point on a curve <C3d> at the distance <eltSize>
262       // from the point of parameter <param>.
263       GCPnts_AbscissaPoint Discret( C3d, eltSize, param );
264       if ( !Discret.IsDone() ) break;
265       param = Discret.Parameter();
266       if ( param < Un )
267         theParams.push_back( param );
268       else
269         break;
270       eltSize *= q;
271     }
272     if ( a1 + an < length ) {
273       // compensate error
274       double Ln = GCPnts_AbscissaPoint::Length( C3d, theParams.back(), Un );
275       double dLn = an - Ln;
276       if ( dLn < 0.5 * an )
277         dLn = -dLn;
278       else {
279         theParams.pop_back();
280         Ln = GCPnts_AbscissaPoint::Length( C3d, theParams.back(), Un );
281         dLn = an - Ln;
282         if ( dLn < 0.5 * an )
283           dLn = -dLn;
284       }
285       double dUn = dLn * ( Un - U1 ) / length;
286 //       SCRUTE( Ln );
287 //       SCRUTE( dLn );
288 //       SCRUTE( dUn );
289       list<double>::reverse_iterator itU = theParams.rbegin();
290       int i, n = theParams.size();
291       for ( i = 1 ; i < n; itU++, i++ ) {
292         (*itU) += dUn;
293         dUn /= q;
294       }
295     }
296
297     return true;
298   }
299
300   case DEFLECTION: {
301
302     GCPnts_UniformDeflection Discret(C3d, _value[ DEFLECTION_IND ], true);
303     if ( !Discret.IsDone() )
304       return false;
305
306     int NbPoints = Discret.NbPoints();
307     for ( int i = 2; i < NbPoints; i++ )
308     {
309       double param = Discret.Parameter(i);
310       theParams.push_back( param );
311     }
312     return true;
313     
314   }
315
316   case ARITHMETIC_1D: {
317         // arithmetic progression: SUM(n) = ( an - a1 + q ) * ( a1 + an ) / ( 2 * q ) = length
318
319     double a1 = _value[ BEG_LENGTH_IND ];
320     double an = _value[ END_LENGTH_IND ];
321
322     double nd = (2 * length) / (an + a1) - 1;
323     int n = int(nd);
324     if(n != nd)
325       n++;
326
327     double q = ((2 * length) / (n + 1) - 2 * a1) / n;
328     double U1 = Min ( f, l );
329     double Un = Max ( f, l );
330     double param = U1;
331     double eltSize = a1;
332
333     double L=0;
334     while ( 1 ) {
335       L+=eltSize;
336       // computes a point on a curve <C3d> at the distance <eltSize>
337       // from the point of parameter <param>.
338       GCPnts_AbscissaPoint Discret( C3d, eltSize, param );
339       if ( !Discret.IsDone() ) break;
340       param = Discret.Parameter();
341       if ( fabs(param - Un) > Precision::Confusion() && param < Un) {
342         theParams.push_back( param );
343       }
344       else
345         break;
346       eltSize += q;
347     }
348
349     return true;
350   }
351
352   default:;
353   }
354
355   return false;
356 }
357
358 //=============================================================================
359 /*!
360  *  
361  */
362 //=============================================================================
363
364 bool StdMeshers_Regular_1D::Compute(SMESH_Mesh & aMesh, const TopoDS_Shape & aShape)
365 {
366   MESSAGE("StdMeshers_Regular_1D::Compute");
367
368   if ( _hypType == NONE )
369     return false;
370
371   SMESHDS_Mesh * meshDS = aMesh.GetMeshDS();
372   aMesh.GetSubMesh(aShape);
373
374   const TopoDS_Edge & EE = TopoDS::Edge(aShape);
375   TopoDS_Edge E = TopoDS::Edge(EE.Oriented(TopAbs_FORWARD));
376
377   double f, l;
378   Handle(Geom_Curve) Curve = BRep_Tool::Curve(E, f, l);
379
380   TopoDS_Vertex VFirst, VLast;
381   TopExp::Vertices(E, VFirst, VLast);   // Vfirst corresponds to f and Vlast to l
382
383   ASSERT(!VFirst.IsNull());
384   SMDS_NodeIteratorPtr lid= aMesh.GetSubMesh(VFirst)->GetSubMeshDS()->GetNodes();
385   if (!lid->more())
386   {
387     MESSAGE (" NO NODE BUILT ON VERTEX ");
388     return false;
389   }
390   const SMDS_MeshNode * idFirst = lid->next();
391
392   ASSERT(!VLast.IsNull());
393   lid=aMesh.GetSubMesh(VLast)->GetSubMeshDS()->GetNodes();
394   if (!lid->more())
395   {
396     MESSAGE (" NO NODE BUILT ON VERTEX ");
397     return false;
398   }
399   const SMDS_MeshNode * idLast = lid->next();
400
401   if (!Curve.IsNull())
402   {
403     list< double > params;
404     try {
405       if ( ! computeInternalParameters( E, params ))
406         return false;
407     }
408     catch ( Standard_Failure ) {
409       return false;
410     }
411
412     // edge extrema (indexes : 1 & NbPoints) already in SMDS (TopoDS_Vertex)
413     // only internal nodes receive an edge position with param on curve
414
415     const SMDS_MeshNode * idPrev = idFirst;
416     
417     for (list<double>::iterator itU = params.begin(); itU != params.end(); itU++)
418     {
419       double param = *itU;
420       gp_Pnt P = Curve->Value(param);
421
422       //Add the Node in the DataStructure
423       SMDS_MeshNode * node = meshDS->AddNode(P.X(), P.Y(), P.Z());
424       meshDS->SetNodeOnEdge(node, E);
425
426       // **** edgePosition associe au point = param. 
427       SMDS_EdgePosition* epos =
428         dynamic_cast<SMDS_EdgePosition *>(node->GetPosition().get());
429       epos->SetUParameter(param);
430
431       SMDS_MeshEdge * edge = meshDS->AddEdge(idPrev, node);
432       meshDS->SetMeshElementOnShape(edge, E);
433       idPrev = node;
434     }
435     SMDS_MeshEdge* edge = meshDS->AddEdge(idPrev, idLast);
436     meshDS->SetMeshElementOnShape(edge, E);
437   }
438   else
439   {
440     // Edge is a degenerated Edge : We put n = 5 points on the edge.
441     int NbPoints = 5;
442     BRep_Tool::Range(E, f, l);
443     double du = (l - f) / (NbPoints - 1);
444     //MESSAGE("************* Degenerated edge! *****************");
445
446     TopoDS_Vertex V1, V2;
447     TopExp::Vertices(E, V1, V2);
448     gp_Pnt P = BRep_Tool::Pnt(V1);
449
450     const SMDS_MeshNode * idPrev = idFirst;
451     for (int i = 2; i < NbPoints; i++)
452     {
453       double param = f + (i - 1) * du;
454       SMDS_MeshNode * node = meshDS->AddNode(P.X(), P.Y(), P.Z());
455       meshDS->SetNodeOnEdge(node, E);
456
457       SMDS_EdgePosition* epos =
458         dynamic_cast<SMDS_EdgePosition*>(node->GetPosition().get());
459       epos->SetUParameter(param);
460
461       SMDS_MeshEdge * edge = meshDS->AddEdge(idPrev, node);
462       meshDS->SetMeshElementOnShape(edge, E);
463       idPrev = node;
464     }
465     SMDS_MeshEdge * edge = meshDS->AddEdge(idPrev, idLast);
466     meshDS->SetMeshElementOnShape(edge, E);
467   }
468   return true;
469 }
470
471 //=============================================================================
472 /*!
473  *  See comments in SMESH_Algo.cxx
474  */
475 //=============================================================================
476
477 const list <const SMESHDS_Hypothesis *> & StdMeshers_Regular_1D::GetUsedHypothesis(
478         SMESH_Mesh & aMesh, const TopoDS_Shape & aShape)
479 {
480   _usedHypList.clear();
481   _usedHypList = GetAppliedHypothesis(aMesh, aShape);   // copy
482   int nbHyp = _usedHypList.size();
483   if (nbHyp == 0)
484   {
485     // Check, if propagated from some other edge
486     TopoDS_Shape aMainEdge;
487     if (aShape.ShapeType() == TopAbs_EDGE &&
488         aMesh.IsPropagatedHypothesis(aShape, aMainEdge))
489     {
490       // Propagation of 1D hypothesis from <aMainEdge> on this edge
491       _usedHypList = GetAppliedHypothesis(aMesh, aMainEdge);    // copy
492       nbHyp = _usedHypList.size();
493     }
494   }
495   if (nbHyp == 0)
496   {
497     TopTools_ListIteratorOfListOfShape ancIt( aMesh.GetAncestors( aShape ));
498     for (; ancIt.More(); ancIt.Next())
499     {
500       const TopoDS_Shape& ancestor = ancIt.Value();
501       _usedHypList = GetAppliedHypothesis(aMesh, ancestor);     // copy
502       nbHyp = _usedHypList.size();
503       if (nbHyp == 1)
504         break;
505     }
506   }
507   if (nbHyp > 1)
508     _usedHypList.clear();       //only one compatible hypothesis allowed
509   return _usedHypList;
510 }
511
512 //=============================================================================
513 /*!
514  *  
515  */
516 //=============================================================================
517
518 ostream & StdMeshers_Regular_1D::SaveTo(ostream & save)
519 {
520   return save;
521 }
522
523 //=============================================================================
524 /*!
525  *  
526  */
527 //=============================================================================
528
529 istream & StdMeshers_Regular_1D::LoadFrom(istream & load)
530 {
531   return load;
532 }
533
534 //=============================================================================
535 /*!
536  *  
537  */
538 //=============================================================================
539
540 ostream & operator <<(ostream & save, StdMeshers_Regular_1D & hyp)
541 {
542   return hyp.SaveTo( save );
543 }
544
545 //=============================================================================
546 /*!
547  *  
548  */
549 //=============================================================================
550
551 istream & operator >>(istream & load, StdMeshers_Regular_1D & hyp)
552 {
553   return hyp.LoadFrom( load );
554 }