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