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