Back to index

salome-smesh  6.5.0
StdMeshers_CompositeSegment_1D.cxx
Go to the documentation of this file.
00001 // Copyright (C) 2007-2012  CEA/DEN, EDF R&D, OPEN CASCADE
00002 //
00003 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
00004 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
00005 //
00006 // This library is free software; you can redistribute it and/or
00007 // modify it under the terms of the GNU Lesser General Public
00008 // License as published by the Free Software Foundation; either
00009 // version 2.1 of the License.
00010 //
00011 // This library is distributed in the hope that it will be useful,
00012 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014 // Lesser General Public License for more details.
00015 //
00016 // You should have received a copy of the GNU Lesser General Public
00017 // License along with this library; if not, write to the Free Software
00018 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
00019 //
00020 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
00021 //
00022 
00023 //  SMESH SMESH : implementaion of SMESH idl descriptions
00024 //  File   : StdMeshers_CompositeSegment_1D.cxx
00025 //  Module : SMESH
00026 //
00027 #include "StdMeshers_CompositeSegment_1D.hxx"
00028 #include "StdMeshers_FaceSide.hxx"
00029 #include "StdMeshers_AutomaticLength.hxx"
00030 
00031 #include "SMESH_Gen.hxx"
00032 #include "SMESH_Mesh.hxx"
00033 #include "SMESH_HypoFilter.hxx"
00034 #include "SMESH_subMesh.hxx"
00035 #include "SMESH_subMeshEventListener.hxx"
00036 #include "SMESH_Comment.hxx"
00037 
00038 #include "SMDS_MeshElement.hxx"
00039 #include "SMDS_MeshNode.hxx"
00040 
00041 #include "utilities.h"
00042 
00043 #include <BRepAdaptor_CompCurve.hxx>
00044 #include <BRep_Builder.hxx>
00045 #include <GCPnts_AbscissaPoint.hxx>
00046 #include <TopExp.hxx>
00047 #include <TopExp_Explorer.hxx>
00048 #include <TopTools_ListIteratorOfListOfShape.hxx>
00049 #include <TopTools_MapOfShape.hxx>
00050 #include <TopoDS.hxx>
00051 #include <TopoDS_Edge.hxx>
00052 #include <TopoDS_Vertex.hxx>
00053 #include <TopoDS_Wire.hxx>
00054 #include <gp_Pnt.hxx>
00055 
00056 #include <Standard_ErrorHandler.hxx>
00057 #include <Standard_Failure.hxx>
00058 
00059 typedef SMESH_Comment TComm;
00060 
00061 using namespace std;
00062 
00063 
00064 namespace {
00065 
00066   //================================================================================
00072   //================================================================================
00073 
00074   TopoDS_Edge nextC1Edge(TopoDS_Edge  edge,
00075                          SMESH_Mesh & aMesh,
00076                          const bool   forward)
00077   {
00078     if (edge.Orientation() > TopAbs_REVERSED) // INTERNAL
00079       edge.Orientation( TopAbs_FORWARD );
00080     TopoDS_Edge eNext;
00081     TopTools_MapOfShape edgeCounter;
00082     edgeCounter.Add( edge );
00083     TopoDS_Vertex v = forward ? TopExp::LastVertex(edge,true) : TopExp::FirstVertex(edge,true);
00084     TopTools_ListIteratorOfListOfShape ancestIt = aMesh.GetAncestors( v );
00085     for ( ; ancestIt.More(); ancestIt.Next() )
00086     {
00087       const TopoDS_Shape & ancestor = ancestIt.Value();
00088       if ( ancestor.ShapeType() == TopAbs_EDGE && edgeCounter.Add( ancestor ))
00089         eNext = TopoDS::Edge( ancestor );
00090     }
00091     if ( edgeCounter.Extent() < 3 && !eNext.IsNull() ) {
00092       if ( SMESH_Algo::IsContinuous( edge, eNext )) {
00093         // care of orientation
00094         if (eNext.Orientation() > TopAbs_REVERSED) // INTERNAL
00095           eNext.Orientation( TopAbs_FORWARD );
00096         TopoDS_Vertex vn =
00097           forward ? TopExp::FirstVertex(eNext,true) : TopExp::LastVertex(eNext,true);
00098         bool reverse = (!v.IsSame(vn));
00099         if ( reverse )
00100           eNext.Reverse();
00101         return eNext;
00102       }
00103     }
00104     return TopoDS_Edge();
00105   }
00106 
00107   //================================================================================
00112   //================================================================================
00113 
00114   void careOfSubMeshes( StdMeshers_FaceSide& side, EventListener* eListener)
00115   {
00116     if ( side.NbEdges() < 2)
00117       return;
00118     for ( int iE = 0; iE < side.NbEdges(); ++iE )
00119     {
00120       // set listener and its data
00121       EventListenerData * listenerData = new EventListenerData(true);
00122       const TopoDS_Edge& edge = side.Edge( iE );
00123       SMESH_subMesh * sm = side.GetMesh()->GetSubMesh( edge );
00124       sm->SetEventListener( eListener, listenerData, sm );
00125       // add edge submesh to the data
00126       sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
00127       if ( sm->GetComputeState() != SMESH_subMesh::COMPUTE_OK ) {
00128         sm->SetIsAlwaysComputed( true );
00129         listenerData->mySubMeshes.push_back( sm );
00130       }
00131       // add internal vertex submesh to the data
00132       if ( iE )
00133       {
00134         TopoDS_Vertex V = side.FirstVertex( iE );
00135         sm = side.GetMesh()->GetSubMesh( V );
00136         sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
00137         if ( sm->GetComputeState() != SMESH_subMesh::COMPUTE_OK )
00138           sm->SetIsAlwaysComputed( true );
00139         listenerData->mySubMeshes.push_back( sm );
00140       }
00141     }
00142   }
00143 
00144   //================================================================================
00149   //================================================================================
00150 
00151   struct VertexNodesRestoringListener : public SMESH_subMeshEventListener
00152   {
00153     VertexNodesRestoringListener():
00154       SMESH_subMeshEventListener(0, // won't be deleted by submesh
00155                                  "StdMeshers_CompositeSegment_1D::VertexNodesRestoringListener")
00156     {}
00165     void ProcessEvent(const int          event,
00166                       const int          eventType,
00167                       SMESH_subMesh*     subMesh,
00168                       EventListenerData* data,
00169                       const SMESH_Hypothesis*  /*hyp*/)
00170     {
00171       if ( data && eventType == SMESH_subMesh::ALGO_EVENT )
00172       {
00173         bool hypRemoved;
00174         if ( subMesh->GetAlgoState() != SMESH_subMesh::HYP_OK )
00175           hypRemoved = true;
00176         else {
00177           SMESH_Algo* algo = subMesh->GetAlgo();
00178           hypRemoved = ( string( algo->GetName() ) != StdMeshers_CompositeSegment_1D::AlgoName());
00179         }
00180         if ( hypRemoved )
00181         {
00182           list<SMESH_subMesh*>::iterator smIt = data->mySubMeshes.begin();
00183           for ( ; smIt != data->mySubMeshes.end(); ++smIt )
00184             if ( SMESH_subMesh* sm = *smIt ) {
00185               sm->SetIsAlwaysComputed( false );
00186               sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
00187             }
00188         }
00189       }
00190       // at study restoration:
00191       // check if edge submesh must have _alwaysComputed flag
00192       else if ( event     == SMESH_subMesh::SUBMESH_RESTORED &&
00193                 eventType == SMESH_subMesh::COMPUTE_EVENT )
00194       {
00195         if ( !subMesh->GetEventListenerData( this )) { // not yet checked
00196           SMESHDS_Mesh * meshDS = subMesh->GetFather()->GetMeshDS();
00197           if ( meshDS->NbNodes() > 0 ) {
00198             // check if there are nodes on all vertices
00199             bool hasNodesOnVerext = true;
00200             SMESH_subMeshIteratorPtr smIt = subMesh->getDependsOnIterator(false,false);
00201             while ( hasNodesOnVerext && smIt->more() ) {
00202               SMESH_subMesh* sm = smIt->next();
00203               hasNodesOnVerext = ( sm->GetSubMeshDS() && sm->GetSubMeshDS()->NbNodes() );
00204             }
00205             if ( !hasNodesOnVerext ) {
00206               // check if an edge is a part of a complex side
00207               TopoDS_Face face;
00208               TopoDS_Edge edge = TopoDS::Edge( subMesh->GetSubShape() );
00209               auto_ptr< StdMeshers_FaceSide > side
00210                 ( StdMeshers_CompositeSegment_1D::GetFaceSide(*subMesh->GetFather(),
00211                                                               edge, face, false ));
00212               if ( side->NbEdges() > 1 && side->NbSegments() )
00213                 careOfSubMeshes( *side, this );
00214             }
00215           }
00216         }
00217       }
00218     }
00219   }; // struct VertexNodesRestoringListener
00220 }
00221 
00222 //=============================================================================
00226 //=============================================================================
00227 
00228 StdMeshers_CompositeSegment_1D::StdMeshers_CompositeSegment_1D(int         hypId,
00229                                                                int         studyId,
00230                                                                SMESH_Gen * gen)
00231   :StdMeshers_Regular_1D(hypId, studyId, gen)
00232 {
00233   MESSAGE("StdMeshers_CompositeSegment_1D::StdMeshers_CompositeSegment_1D");
00234   _name = AlgoName();
00235   _EventListener = new VertexNodesRestoringListener();
00236 }
00237 
00238 //=======================================================================
00239 //function : AlgoName
00240 //purpose  : Returns algo type name
00241 //=======================================================================
00242 
00243 std::string StdMeshers_CompositeSegment_1D::AlgoName()
00244 {
00245   return "CompositeSegment_1D";
00246 }
00247 //=============================================================================
00251 //=============================================================================
00252 
00253 StdMeshers_CompositeSegment_1D::~StdMeshers_CompositeSegment_1D()
00254 {
00255   delete _EventListener;
00256 }
00257 
00258 //=============================================================================
00266 //=============================================================================
00267 
00268 void StdMeshers_CompositeSegment_1D::SetEventListener(SMESH_subMesh* subMesh)
00269 {
00270   // issue 0020279. Set "_alwaysComputed" flag to the submeshes of internal
00271   // vertices of composite edge in order to avoid creation of vertices on
00272   // them for the sake of stability.
00273 
00274   // check if "_alwaysComputed" is not yet set
00275   bool isAlwaysComputed = false;
00276   SMESH_subMeshIteratorPtr smIt = subMesh->getDependsOnIterator(false,false);
00277   while ( !isAlwaysComputed && smIt->more() )
00278     isAlwaysComputed = smIt->next()->IsAlwaysComputed();
00279 
00280   if ( !isAlwaysComputed )
00281   {
00282     // check if an edge is a part of a complex side
00283     TopoDS_Face face;
00284     TopoDS_Edge edge = TopoDS::Edge( subMesh->GetSubShape() );
00285     auto_ptr< StdMeshers_FaceSide > side
00286       ( StdMeshers_CompositeSegment_1D::GetFaceSide(*subMesh->GetFather(),edge, face, false ));
00287     if ( side->NbEdges() > 1 ) { // complex
00288 
00289       // set _alwaysComputed to vertices
00290       for ( int iE = 1; iE < side->NbEdges(); ++iE )
00291       {
00292         TopoDS_Vertex V = side->FirstVertex( iE );
00293         SMESH_subMesh* sm = side->GetMesh()->GetSubMesh( V );
00294         sm->SetIsAlwaysComputed( true );
00295       }
00296     }
00297   }
00298   // set listener that will remove _alwaysComputed from submeshes at algorithm change
00299   subMesh->SetEventListener( _EventListener, 0, subMesh);
00300   StdMeshers_Regular_1D::SetEventListener( subMesh );
00301 }
00302 
00303 //=============================================================================
00307 //=============================================================================
00308 
00309 StdMeshers_FaceSide *
00310 StdMeshers_CompositeSegment_1D::GetFaceSide(SMESH_Mesh&        aMesh,
00311                                             const TopoDS_Edge& anEdge,
00312                                             const TopoDS_Face& aFace,
00313                                             const bool         ignoreMeshed)
00314 {
00315   list< TopoDS_Edge > edges;
00316   if ( anEdge.Orientation() <= TopAbs_REVERSED )
00317     edges.push_back( anEdge );
00318   else
00319     edges.push_back( TopoDS::Edge( anEdge.Oriented( TopAbs_FORWARD ))); // PAL21718
00320 
00321   list <const SMESHDS_Hypothesis *> hypList;
00322   SMESH_Algo* theAlgo = aMesh.GetGen()->GetAlgo( aMesh, anEdge );
00323   if ( theAlgo ) hypList = theAlgo->GetUsedHypothesis(aMesh, anEdge, false);
00324   for ( int forward = 0; forward < 2; ++forward )
00325   {
00326     TopoDS_Edge eNext = nextC1Edge( edges.back(), aMesh, forward );
00327     while ( !eNext.IsNull() ) {
00328       if ( ignoreMeshed ) {
00329         // eNext must not have computed mesh
00330         if ( SMESHDS_SubMesh* sm = aMesh.GetMeshDS()->MeshElements(eNext) )
00331           if ( sm->NbNodes() || sm->NbElements() )
00332             break;
00333       }
00334       // eNext must have same hypotheses
00335       SMESH_Algo* algo = aMesh.GetGen()->GetAlgo( aMesh, eNext );
00336       if ( !algo ||
00337            string(theAlgo->GetName()) != algo->GetName() ||
00338            hypList != algo->GetUsedHypothesis(aMesh, eNext, false))
00339         break;
00340       if ( std::find( edges.begin(), edges.end(), eNext ) != edges.end() )
00341         break;
00342       if ( forward )
00343         edges.push_back( eNext );
00344       else
00345         edges.push_front( eNext );
00346       eNext = nextC1Edge( eNext, aMesh, forward );
00347     }
00348   }
00349   return new StdMeshers_FaceSide( aFace, edges, &aMesh, true, false );
00350 }
00351 
00352 //=============================================================================
00356 //=============================================================================
00357 
00358 bool StdMeshers_CompositeSegment_1D::Compute(SMESH_Mesh &         aMesh,
00359                                              const TopoDS_Shape & aShape)
00360 {
00361   TopoDS_Edge edge = TopoDS::Edge( aShape );
00362   SMESHDS_Mesh * meshDS = aMesh.GetMeshDS();
00363 
00364   // Get edges to be discretized as a whole
00365   TopoDS_Face nullFace;
00366   auto_ptr< StdMeshers_FaceSide > side( GetFaceSide(aMesh, edge, nullFace, true ));
00367   //side->dump("IN COMPOSITE SEG");
00368 
00369   if ( side->NbEdges() < 2 )
00370     return StdMeshers_Regular_1D::Compute( aMesh, aShape );
00371 
00372   // update segment lenght computed by StdMeshers_AutomaticLength
00373   const list <const SMESHDS_Hypothesis * > & hyps = GetUsedHypothesis(aMesh, aShape);
00374   if ( !hyps.empty() ) {
00375     StdMeshers_AutomaticLength * autoLenHyp = const_cast<StdMeshers_AutomaticLength *>
00376       (dynamic_cast <const StdMeshers_AutomaticLength * >(hyps.front()));
00377     if ( autoLenHyp )
00378       _value[ BEG_LENGTH_IND ]= autoLenHyp->GetLength( &aMesh, side->Length() );
00379   }
00380 
00381   // Compute node parameters
00382   auto_ptr< BRepAdaptor_CompCurve > C3d ( side->GetCurve3d() );
00383   double f = C3d->FirstParameter(), l = C3d->LastParameter();
00384   list< double > params;
00385   if ( !computeInternalParameters ( aMesh, *C3d, side->Length(), f, l, params, false ))
00386     return false;
00387 
00388   // Redistribute parameters near ends
00389   TopoDS_Vertex VFirst = side->FirstVertex();
00390   TopoDS_Vertex VLast  = side->LastVertex();
00391   redistributeNearVertices( aMesh, *C3d, side->Length(), params, VFirst, VLast );
00392 
00393   params.push_front(f);
00394   params.push_back(l);
00395   int nbNodes = params.size();
00396 
00397   // Create mesh
00398 
00399   const SMDS_MeshNode * nFirst = SMESH_Algo::VertexNode( VFirst, meshDS );
00400   const SMDS_MeshNode * nLast  = SMESH_Algo::VertexNode( VLast, meshDS );
00401   if (!nFirst)
00402     return error(COMPERR_BAD_INPUT_MESH, TComm("No node on vertex ")
00403                  <<meshDS->ShapeToIndex(VFirst));
00404   if (!nLast)
00405     return error(COMPERR_BAD_INPUT_MESH, TComm("No node on vertex ")
00406                  <<meshDS->ShapeToIndex(VLast));
00407 
00408   vector<const SMDS_MeshNode*> nodes( nbNodes, (const SMDS_MeshNode*)0 );
00409   nodes.front() = nFirst;
00410   nodes.back()  = nLast;
00411 
00412   // create internal nodes
00413   list< double >::iterator parIt = params.begin();
00414   double prevPar = *parIt;
00415   Standard_Real u;
00416   for ( int iN = 0; parIt != params.end(); ++iN, ++parIt)
00417   {
00418     if ( !nodes[ iN ] ) {
00419       gp_Pnt p = C3d->Value( *parIt );
00420       SMDS_MeshNode* n = meshDS->AddNode( p.X(), p.Y(), p.Z());
00421       C3d->Edge( *parIt, edge, u );
00422       meshDS->SetNodeOnEdge( n, edge, u );
00423 //       cout << "new NODE: par="<<*parIt<<" ePar="<<u<<" e="<<edge.TShape().operator->()
00424 //            << " " << n << endl;
00425       nodes[ iN ] = n;
00426     }
00427     // create edges
00428     if ( iN ) {
00429       double mPar = ( prevPar + *parIt )/2;
00430       if ( _quadraticMesh ) {
00431         // create medium node
00432         double segLen = GCPnts_AbscissaPoint::Length(*C3d, prevPar, *parIt);
00433         GCPnts_AbscissaPoint ruler( *C3d, segLen/2., prevPar );
00434         if ( ruler.IsDone() )
00435           mPar = ruler.Parameter();
00436         gp_Pnt p = C3d->Value( mPar );
00437         SMDS_MeshNode* n = meshDS->AddNode( p.X(), p.Y(), p.Z());
00438         //cout << "new NODE "<< n << endl;
00439         meshDS->SetNodeOnEdge( n, edge, u );
00440         SMDS_MeshEdge * seg = meshDS->AddEdge(nodes[ iN-1 ], nodes[ iN ], n);
00441         meshDS->SetMeshElementOnShape(seg, edge);
00442       }
00443       else {
00444         C3d->Edge( mPar, edge, u );
00445         SMDS_MeshEdge * seg = meshDS->AddEdge(nodes[ iN-1 ], nodes[ iN ]);
00446         meshDS->SetMeshElementOnShape(seg, edge);
00447       }
00448     }
00449     prevPar = *parIt;
00450   }
00451 
00452   // remove nodes on internal vertices
00453   for ( int iE = 1; iE < side->NbEdges(); ++iE )
00454   {
00455     TopoDS_Vertex V = side->FirstVertex( iE );
00456     while ( const SMDS_MeshNode * n = SMESH_Algo::VertexNode( V, meshDS ))
00457       meshDS->RemoveNode( n );
00458   }
00459 
00460   // Update submeshes state for all edges and internal vertices,
00461   // make them look computed even if none edge or node is set on them
00462   careOfSubMeshes( *side, _EventListener );
00463 
00464   return true;
00465 }