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