Salome HOME
Merge from V5_1_4_BR 07/05/2010
[modules/smesh.git] / src / StdMeshers / StdMeshers_CompositeSegment_1D.cxx
1 //  Copyright (C) 2007-2010  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 //  SMESH SMESH : implementaion of SMESH idl descriptions
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 #include "StdMeshers_CompositeSegment_1D.hxx"
31 #include "StdMeshers_FaceSide.hxx"
32 #include "StdMeshers_AutomaticLength.hxx"
33
34 #include "SMESH_Gen.hxx"
35 #include "SMESH_Mesh.hxx"
36 #include "SMESH_HypoFilter.hxx"
37 #include "SMESH_subMesh.hxx"
38 #include "SMESH_subMeshEventListener.hxx"
39 #include "SMESH_Comment.hxx"
40
41 #include "SMDS_MeshElement.hxx"
42 #include "SMDS_MeshNode.hxx"
43
44 #include "utilities.h"
45
46 #include <BRepAdaptor_CompCurve.hxx>
47 #include <BRep_Builder.hxx>
48 #include <GCPnts_AbscissaPoint.hxx>
49 #include <TopExp.hxx>
50 #include <TopExp_Explorer.hxx>
51 #include <TopTools_ListIteratorOfListOfShape.hxx>
52 #include <TopTools_MapOfShape.hxx>
53 #include <TopoDS.hxx>
54 #include <TopoDS_Edge.hxx>
55 #include <TopoDS_Vertex.hxx>
56 #include <TopoDS_Wire.hxx>
57 #include <gp_Pnt.hxx>
58
59 #include <Standard_ErrorHandler.hxx>
60 #include <Standard_Failure.hxx>
61
62 typedef SMESH_Comment TComm;
63
64 using namespace std;
65
66
67 namespace {
68
69   //================================================================================
70   /*!
71    * \brief Search for an edge conjunct to the given one by the vertex
72    *        Return NULL if more than 2 edges share the vertex or edges
73    *        continuity is less than C1
74    */
75   //================================================================================
76
77   TopoDS_Edge nextC1Edge(TopoDS_Edge  edge,
78                          SMESH_Mesh & aMesh,
79                          const bool   forward)
80   {
81     if (edge.Orientation() > TopAbs_REVERSED) // INTERNAL
82       edge.Orientation( TopAbs_FORWARD );
83     TopoDS_Edge eNext;
84     TopTools_MapOfShape edgeCounter;
85     edgeCounter.Add( edge );
86     TopoDS_Vertex v = forward ? TopExp::LastVertex(edge,true) : TopExp::FirstVertex(edge,true);
87     TopTools_ListIteratorOfListOfShape ancestIt = aMesh.GetAncestors( v );
88     for ( ; ancestIt.More(); ancestIt.Next() )
89     {
90       const TopoDS_Shape & ancestor = ancestIt.Value();
91       if ( ancestor.ShapeType() == TopAbs_EDGE && edgeCounter.Add( ancestor ))
92         eNext = TopoDS::Edge( ancestor );
93     }
94     if ( edgeCounter.Extent() < 3 && !eNext.IsNull() ) {
95       if ( SMESH_Algo::IsContinuous( edge, eNext )) {
96         // care of orientation
97         if (eNext.Orientation() > TopAbs_REVERSED) // INTERNAL
98           eNext.Orientation( TopAbs_FORWARD );
99         TopoDS_Vertex vn =
100           forward ? TopExp::FirstVertex(eNext,true) : TopExp::LastVertex(eNext,true);
101         bool reverse = (!v.IsSame(vn));
102         if ( reverse )
103           eNext.Reverse();
104         return eNext;
105       }
106     }
107     return TopoDS_Edge();
108   }
109
110   //================================================================================
111   /*!
112    * \brief Update submeshes state for all edges and internal vertices,
113    * make them look computed even if none edge or node is set on them
114    */
115   //================================================================================
116
117   void careOfSubMeshes( StdMeshers_FaceSide& side, EventListener* eListener)
118   {
119     if ( side.NbEdges() < 2)
120       return;
121     for ( int iE = 0; iE < side.NbEdges(); ++iE )
122     {
123       // set listener and its data
124       EventListenerData * listenerData = new EventListenerData(true);
125       const TopoDS_Edge& edge = side.Edge( iE );
126       SMESH_subMesh * sm = side.GetMesh()->GetSubMesh( edge );
127       sm->SetEventListener( eListener, listenerData, sm );
128       // add edge submesh to the data
129       sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
130       if ( sm->GetComputeState() != SMESH_subMesh::COMPUTE_OK ) {
131         sm->SetIsAlwaysComputed( true );
132         listenerData->mySubMeshes.push_back( sm );
133       }
134       // add internal vertex submesh to the data
135       if ( iE )
136       {
137         TopoDS_Vertex V = side.FirstVertex( iE );
138         sm = side.GetMesh()->GetSubMesh( V );
139         sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
140         if ( sm->GetComputeState() != SMESH_subMesh::COMPUTE_OK )
141           sm->SetIsAlwaysComputed( true );
142         listenerData->mySubMeshes.push_back( sm );
143       }
144     }
145   }
146
147   //================================================================================
148   /*!
149    * \brief Class used to restore nodes on internal vertices of a complex side
150    *  when StdMeshers_CompositeSegment_1D algorithm is removed
151    */
152   //================================================================================
153
154   struct VertexNodesRestoringListener : public SMESH_subMeshEventListener
155   {
156     VertexNodesRestoringListener():SMESH_subMeshEventListener(0) // won't be deleted by submesh
157     {}
158   /*!
159    * \brief Restore nodes on internal vertices of a complex side
160    * \param event - algo_event or compute_event itself (of SMESH_subMesh)
161    * \param eventType - ALGO_EVENT or COMPUTE_EVENT (of SMESH_subMesh)
162    * \param subMesh - the submesh where the event occures
163    * \param data - listener data stored in the subMesh
164    * \param hyp - hypothesis, if eventType is algo_event
165    */
166     void ProcessEvent(const int          event,
167                       const int          eventType,
168                       SMESH_subMesh*     subMesh,
169                       EventListenerData* data,
170                       const SMESH_Hypothesis*  /*hyp*/)
171     {
172       bool hypRemoved = ( eventType == SMESH_subMesh::ALGO_EVENT &&
173                           subMesh->GetAlgoState() != SMESH_subMesh::HYP_OK );
174       if ( hypRemoved && data )
175       {
176         list<SMESH_subMesh*>::iterator smIt = data->mySubMeshes.begin();
177         for ( ; smIt != data->mySubMeshes.end(); ++smIt )
178         {
179           if ( SMESH_subMesh* sm = *smIt ) {
180             sm->SetIsAlwaysComputed( false );
181             sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
182           }
183         }
184       }
185       // at study restoration:
186       // check if edge submesh must have _alwaysComputed flag
187       else if ( event     == SMESH_subMesh::SUBMESH_RESTORED &&
188                 eventType == SMESH_subMesh::COMPUTE_EVENT )
189       {
190         if ( !subMesh->GetEventListenerData( this )) { // not yet checked
191           SMESHDS_Mesh * meshDS = subMesh->GetFather()->GetMeshDS();
192           if ( meshDS->NbNodes() > 0 ) {
193             // check if there are nodes on all vertices
194             bool hasNodesOnVerext = true;
195             SMESH_subMeshIteratorPtr smIt = subMesh->getDependsOnIterator(false,false);
196             while ( hasNodesOnVerext && smIt->more() ) {
197               SMESH_subMesh* sm = smIt->next();
198               hasNodesOnVerext = ( sm->GetSubMeshDS() && sm->GetSubMeshDS()->NbNodes() );
199             }
200             if ( !hasNodesOnVerext ) {
201               // check if an edge is a part of a complex side
202               TopoDS_Face face;
203               TopoDS_Edge edge = TopoDS::Edge( subMesh->GetSubShape() );
204               auto_ptr< StdMeshers_FaceSide > side
205                 ( StdMeshers_CompositeSegment_1D::GetFaceSide(*subMesh->GetFather(),
206                                                               edge, face, false ));
207               if ( side->NbEdges() > 1 && side->NbSegments() )
208                 careOfSubMeshes( *side, this );
209             }
210           }
211         }
212       }
213     }
214   }; // struct VertexNodesRestoringListener
215 }
216
217 //=============================================================================
218 /*!
219  *  
220  */
221 //=============================================================================
222
223 StdMeshers_CompositeSegment_1D::StdMeshers_CompositeSegment_1D(int         hypId,
224                                                                int         studyId,
225                                                                SMESH_Gen * gen)
226   :StdMeshers_Regular_1D(hypId, studyId, gen)
227 {
228   MESSAGE("StdMeshers_CompositeSegment_1D::StdMeshers_CompositeSegment_1D");
229   _name = "CompositeSegment_1D";
230   _EventListener = new VertexNodesRestoringListener();
231 }
232
233 //=============================================================================
234 /*!
235  *  
236  */
237 //=============================================================================
238
239 StdMeshers_CompositeSegment_1D::~StdMeshers_CompositeSegment_1D()
240 {
241   delete _EventListener;
242 }
243
244 //=============================================================================
245 /*!
246  * \brief Sets event listener to submeshes if necessary
247  * \param subMesh - submesh where algo is set
248  *
249  * This method is called when a submesh gets HYP_OK algo_state.
250  * After being set, event listener is notified on each event of a submesh.
251  */
252 //=============================================================================
253
254 void StdMeshers_CompositeSegment_1D::SetEventListener(SMESH_subMesh* subMesh)
255 {
256   // issue 0020279. Set "_alwaysComputed" flag to the submeshes of internal
257   // vertices of composite edge in order to avoid creation of vertices on
258   // them for the sake of stability.
259
260   // check if "_alwaysComputed" is not yet set
261   bool isAlwaysComputed = false;
262   SMESH_subMeshIteratorPtr smIt = subMesh->getDependsOnIterator(false,false);
263   while ( !isAlwaysComputed && smIt->more() )
264     isAlwaysComputed = smIt->next()->IsAlwaysComputed();
265
266   if ( !isAlwaysComputed )
267   {
268     // check if an edge is a part of a complex side
269     TopoDS_Face face;
270     TopoDS_Edge edge = TopoDS::Edge( subMesh->GetSubShape() );
271     auto_ptr< StdMeshers_FaceSide > side
272       ( StdMeshers_CompositeSegment_1D::GetFaceSide(*subMesh->GetFather(),edge, face, false ));
273     if ( side->NbEdges() > 1 ) { // complex
274
275       // set _alwaysComputed to vertices
276       for ( int iE = 1; iE < side->NbEdges(); ++iE )
277       {
278         TopoDS_Vertex V = side->FirstVertex( iE );
279         SMESH_subMesh* sm = side->GetMesh()->GetSubMesh( V );
280         sm->SetIsAlwaysComputed( true );
281       }
282     }
283   }
284   // set listener that will remove _alwaysComputed from submeshes at algorithm change
285   subMesh->SetEventListener( _EventListener, 0, subMesh);
286   StdMeshers_Regular_1D::SetEventListener( subMesh );
287 }
288
289 //=============================================================================
290 /*!
291  * \brief Return a face side the edge belongs to
292  */
293 //=============================================================================
294
295 StdMeshers_FaceSide *
296 StdMeshers_CompositeSegment_1D::GetFaceSide(SMESH_Mesh&        aMesh,
297                                             const TopoDS_Edge& anEdge,
298                                             const TopoDS_Face& aFace,
299                                             const bool         ignoreMeshed)
300 {
301   list< TopoDS_Edge > edges;
302   if ( anEdge.Orientation() <= TopAbs_REVERSED )
303     edges.push_back( anEdge );
304   else
305     edges.push_back( TopoDS::Edge( anEdge.Oriented( TopAbs_FORWARD ))); // PAL21718
306
307   list <const SMESHDS_Hypothesis *> hypList;
308   SMESH_Algo* theAlgo = aMesh.GetGen()->GetAlgo( aMesh, anEdge );
309   if ( theAlgo ) hypList = theAlgo->GetUsedHypothesis(aMesh, anEdge, false);
310   for ( int forward = 0; forward < 2; ++forward )
311   {
312     TopoDS_Edge eNext = nextC1Edge( edges.back(), aMesh, forward );
313     while ( !eNext.IsNull() ) {
314       if ( ignoreMeshed ) {
315         // eNext must not have computed mesh
316         if ( SMESHDS_SubMesh* sm = aMesh.GetMeshDS()->MeshElements(eNext) )
317           if ( sm->NbNodes() || sm->NbElements() )
318             break;
319       }
320       // eNext must have same hypotheses
321       SMESH_Algo* algo = aMesh.GetGen()->GetAlgo( aMesh, eNext );
322       if ( !algo ||
323            string(theAlgo->GetName()) != algo->GetName() ||
324            hypList != algo->GetUsedHypothesis(aMesh, eNext, false))
325         break;
326       if ( forward )
327         edges.push_back( eNext );
328       else
329         edges.push_front( eNext );
330       eNext = nextC1Edge( eNext, aMesh, forward );
331     }
332   }
333   return new StdMeshers_FaceSide( aFace, edges, &aMesh, true, false );
334 }
335
336 //=============================================================================
337 /*!
338  *  
339  */
340 //=============================================================================
341
342 bool StdMeshers_CompositeSegment_1D::Compute(SMESH_Mesh &         aMesh,
343                                              const TopoDS_Shape & aShape)
344 {
345   TopoDS_Edge edge = TopoDS::Edge( aShape );
346   SMESHDS_Mesh * meshDS = aMesh.GetMeshDS();
347
348   // Get edges to be discretized as a whole
349   TopoDS_Face nullFace;
350   auto_ptr< StdMeshers_FaceSide > side( GetFaceSide(aMesh, edge, nullFace, true ));
351   //side->dump("IN COMPOSITE SEG");
352
353   if ( side->NbEdges() < 2 )
354     return StdMeshers_Regular_1D::Compute( aMesh, aShape );
355
356   // update segment lenght computed by StdMeshers_AutomaticLength
357   const list <const SMESHDS_Hypothesis * > & hyps = GetUsedHypothesis(aMesh, aShape);
358   if ( !hyps.empty() ) {
359     StdMeshers_AutomaticLength * autoLenHyp = const_cast<StdMeshers_AutomaticLength *>
360       (dynamic_cast <const StdMeshers_AutomaticLength * >(hyps.front()));
361     if ( autoLenHyp )
362       _value[ BEG_LENGTH_IND ]= autoLenHyp->GetLength( &aMesh, side->Length() );
363   }
364
365   // Compute node parameters
366   auto_ptr< BRepAdaptor_CompCurve > C3d ( side->GetCurve3d() );
367   double f = C3d->FirstParameter(), l = C3d->LastParameter();
368   list< double > params;
369   if ( !computeInternalParameters ( aMesh, *C3d, side->Length(), f, l, params, false ))
370     return false;
371
372   // Redistribute parameters near ends
373   TopoDS_Vertex VFirst = side->FirstVertex();
374   TopoDS_Vertex VLast  = side->LastVertex();
375   redistributeNearVertices( aMesh, *C3d, side->Length(), params, VFirst, VLast );
376
377   params.push_front(f);
378   params.push_back(l);
379   int nbNodes = params.size();
380
381   // Create mesh
382
383   const SMDS_MeshNode * nFirst = SMESH_Algo::VertexNode( VFirst, meshDS );
384   const SMDS_MeshNode * nLast  = SMESH_Algo::VertexNode( VLast, meshDS );
385   if (!nFirst)
386     return error(COMPERR_BAD_INPUT_MESH, TComm("No node on vertex ")
387                  <<meshDS->ShapeToIndex(VFirst));
388   if (!nLast)
389     return error(COMPERR_BAD_INPUT_MESH, TComm("No node on vertex ")
390                  <<meshDS->ShapeToIndex(VLast));
391
392   vector<const SMDS_MeshNode*> nodes( nbNodes, (const SMDS_MeshNode*)0 );
393   nodes.front() = nFirst;
394   nodes.back()  = nLast;
395
396   // create internal nodes
397   list< double >::iterator parIt = params.begin();
398   double prevPar = *parIt;
399   Standard_Real u;
400   for ( int iN = 0; parIt != params.end(); ++iN, ++parIt)
401   {
402     if ( !nodes[ iN ] ) {
403       gp_Pnt p = C3d->Value( *parIt );
404       SMDS_MeshNode* n = meshDS->AddNode( p.X(), p.Y(), p.Z());
405       C3d->Edge( *parIt, edge, u );
406       meshDS->SetNodeOnEdge( n, edge, u );
407 //       cout << "new NODE: par="<<*parIt<<" ePar="<<u<<" e="<<edge.TShape().operator->()
408 //            << " " << n << endl;
409       nodes[ iN ] = n;
410     }
411     // create edges
412     if ( iN ) {
413       double mPar = ( prevPar + *parIt )/2;
414       if ( _quadraticMesh ) {
415         // create medium node
416         double segLen = GCPnts_AbscissaPoint::Length(*C3d, prevPar, *parIt);
417         GCPnts_AbscissaPoint ruler( *C3d, segLen/2., prevPar );
418         if ( ruler.IsDone() )
419           mPar = ruler.Parameter();
420         gp_Pnt p = C3d->Value( mPar );
421         SMDS_MeshNode* n = meshDS->AddNode( p.X(), p.Y(), p.Z());
422         //cout << "new NODE "<< n << endl;
423         meshDS->SetNodeOnEdge( n, edge, u );
424         SMDS_MeshEdge * seg = meshDS->AddEdge(nodes[ iN-1 ], nodes[ iN ], n);
425         meshDS->SetMeshElementOnShape(seg, edge);
426       }
427       else {
428         C3d->Edge( mPar, edge, u );
429         SMDS_MeshEdge * seg = meshDS->AddEdge(nodes[ iN-1 ], nodes[ iN ]);
430         meshDS->SetMeshElementOnShape(seg, edge);
431       }
432     }
433     prevPar = *parIt;
434   }
435
436   // remove nodes on internal vertices
437   for ( int iE = 1; iE < side->NbEdges(); ++iE )
438   {
439     TopoDS_Vertex V = side->FirstVertex( iE );
440     while ( const SMDS_MeshNode * n = SMESH_Algo::VertexNode( V, meshDS ))
441       meshDS->RemoveNode( n );
442   }
443
444   // Update submeshes state for all edges and internal vertices,
445   // make them look computed even if none edge or node is set on them
446   careOfSubMeshes( *side, _EventListener );
447
448   return true;
449 }