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