Salome HOME
#16648 [CEA] RadialQuadrangle algorithm hypothesis change requires a Clear Mesh Data...
[modules/smesh.git] / src / StdMeshers / StdMeshers_RadialQuadrangle_1D2D.cxx
index 4f2329d5932db1ad5f770be021cdb6c6a5a6898f..8c5869107d5e0cc5859628bd117bbc22ae3b71bf 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2007-2016  CEA/DEN, EDF R&D, OPEN CASCADE
+// Copyright (C) 2007-2019  CEA/DEN, EDF R&D, OPEN CASCADE
 //
 // This library is free software; you can redistribute it and/or
 // modify it under the terms of the GNU Lesser General Public
@@ -74,9 +74,8 @@ using namespace std;
 //=======================================================================
 
 StdMeshers_RadialQuadrangle_1D2D::StdMeshers_RadialQuadrangle_1D2D(int        hypId,
-                                                                   int        studyId,
                                                                    SMESH_Gen* gen)
-  :StdMeshers_Quadrangle_2D( hypId, studyId, gen )
+  :StdMeshers_Quadrangle_2D( hypId, gen )
 {
   _name = "RadialQuadrangle_1D2D";
   _shapeType = (1 << TopAbs_FACE);        // 1 bit per shape type
@@ -164,38 +163,45 @@ namespace
       static TEdgeMarker theEdgeMarker;
       return &theEdgeMarker;
     }
-    //! Clear face sumbesh if something happens on edges
+    //! Clear edge sumbesh if something happens on face
     void ProcessEvent(const int          event,
                       const int          eventType,
-                      SMESH_subMesh*     edgeSubMesh,
-                      EventListenerData* data,
+                      SMESH_subMesh*     faceSubMesh,
+                      EventListenerData* edgesHolder,
                       const SMESH_Hypothesis*  /*hyp*/)
     {
-      if ( data && !data->mySubMeshes.empty() && eventType == SMESH_subMesh::ALGO_EVENT)
+      if ( edgesHolder && eventType == SMESH_subMesh::ALGO_EVENT)
       {
-        ASSERT( data->mySubMeshes.front() != edgeSubMesh );
-        SMESH_subMesh* faceSubMesh = data->mySubMeshes.front();
-        faceSubMesh->ComputeStateEngine( SMESH_subMesh::CLEAN );
+        std::list<SMESH_subMesh*>::iterator smIt = edgesHolder->mySubMeshes.begin();
+        for ( ; smIt != edgesHolder->mySubMeshes.end(); ++smIt )
+        {
+          SMESH_subMesh* edgeSM = *smIt;
+          edgeSM->ComputeStateEngine( SMESH_subMesh::CLEAN );
+        }
       }
     }
-  };
-
-  //================================================================================
-  /*!
-   * \brief Mark an edge as computed by StdMeshers_RadialQuadrangle_1D2D
-   */
-  //================================================================================
-
-  void markEdgeAsComputedByMe(const TopoDS_Edge& edge, SMESH_subMesh* faceSubMesh)
-  {
-    if ( SMESH_subMesh* edgeSM = faceSubMesh->GetFather()->GetSubMeshContaining( edge ))
+    //! Store edge SMESH_subMesh'es computed by the algo
+    static void markEdge( const TopoDS_Edge& edge, SMESH_subMesh* faceSM )
     {
-      if ( !edgeSM->GetEventListenerData( TEdgeMarker::getListener() ))
-        faceSubMesh->SetEventListener( TEdgeMarker::getListener(),
-                                       SMESH_subMeshEventListenerData::MakeData(faceSubMesh),
-                                       edgeSM);
+      if ( SMESH_subMesh* edgeSM = faceSM->GetFather()->GetSubMeshContaining( edge ))
+      {
+        EventListenerData* edgesHolder = faceSM->GetEventListenerData( getListener() );
+        if ( edgesHolder )
+        {
+          std::list<SMESH_subMesh*>::iterator smIt = std::find( edgesHolder->mySubMeshes.begin(),
+                                                                edgesHolder->mySubMeshes.end(),
+                                                                edgeSM );
+          if ( smIt == edgesHolder->mySubMeshes.end() )
+            edgesHolder->mySubMeshes.push_back( edgeSM );
+        }
+        else
+        {
+          edgesHolder = SMESH_subMeshEventListenerData::MakeData( edgeSM );
+          faceSM->SetEventListener( TEdgeMarker::getListener(), edgesHolder, faceSM );
+        }
+      }
     }
-  }
+  };
 
   //================================================================================
   /*!
@@ -208,7 +214,8 @@ namespace
                   SMESH_Mesh*             aMesh,
                   StdMeshers_FaceSidePtr& aCircSide,
                   StdMeshers_FaceSidePtr& aLinSide1,
-                  StdMeshers_FaceSidePtr& aLinSide2)
+                  StdMeshers_FaceSidePtr& aLinSide2,
+                  SMESH_MesherHelper*     helper)
   {
     const TopoDS_Face& face = TopoDS::Face( aShape );
     aCircSide.reset(); aLinSide1.reset(); aLinSide2.reset();
@@ -259,7 +266,7 @@ namespace
       StdMeshers_FaceSidePtr side;
       if ( aMesh ) 
         side = StdMeshers_FaceSide::New( face, sideEdges, aMesh,
-                                         /*isFwd=*/true, /*skipMedium=*/ true );
+                                         /*isFwd=*/true, /*skipMedium=*/ true, helper );
       sides.push_back( side );
     }
 
@@ -306,6 +313,24 @@ namespace
       }
       deviation2sideInd.insert( make_pair( devia, iS ));
     }
+    double maxDevi = deviation2sideInd.rbegin()->first;
+    if ( maxDevi < 1e-7 && sides.size() == 3 )
+    {
+      // a triangle FACE; use a side with the most outstanding length as an elliptic one
+      deviation2sideInd.clear();
+      multimap< double, int > len2sideInd;
+      for ( size_t iS = 0; iS < sides.size(); ++iS )
+        len2sideInd.insert( make_pair( sides[iS]->Length(), iS ));
+
+      multimap< double, int >::iterator l2i = len2sideInd.begin();
+      double len0 = l2i->first;
+      double len1 = (++l2i)->first;
+      double len2 = (++l2i)->first;
+      if ( len1 - len0 > len2 - len1 )
+        deviation2sideInd.insert( make_pair( 0., len2sideInd.begin()->second ));
+      else
+        deviation2sideInd.insert( make_pair( 0., len2sideInd.rbegin()->second ));
+    }
 
     int iCirc = deviation2sideInd.rbegin()->second; 
     aCircSide = sides[ iCirc ];
@@ -339,7 +364,7 @@ namespace
           edges.push_back( aCircSide->Edge( iE % aCircSide->NbEdges() ));
 
         aCircSide = StdMeshers_FaceSide::New( face, edges, aMesh,
-                                              /*isFwd=*/true, /*skipMedium=*/ true );
+                                              /*isFwd=*/true, /*skipMedium=*/ true, helper );
       }
     }
 
@@ -582,7 +607,7 @@ namespace
     {
       if ( meshDS->FindEdge( nodes[i].node, nodes[i-1].node )) continue;
 
-      const SMDS_MeshElement* seg = meshDS->AddEdge( nodes[i].node, nodes[i-1].node );
+      const SMDS_MeshElement* seg = helper->AddEdge( nodes[i].node, nodes[i-1].node );
 
       double normParam = 0.5 * ( nodes[i].normParam + nodes[i-1].normParam );
       edgeID = linSide->EdgeID( linSide->EdgeIndex( normParam ));
@@ -612,7 +637,7 @@ public:
     const int myID = -1001;
     TNodeDistributor* myHyp = dynamic_cast<TNodeDistributor*>( aMesh.GetHypothesis( myID ));
     if ( !myHyp )
-      myHyp = new TNodeDistributor( myID, 0, aMesh.GetGen() );
+      myHyp = new TNodeDistributor( myID, aMesh.GetGen() );
     return myHyp;
   }
   // -----------------------------------------------------------------------------
@@ -650,7 +675,7 @@ public:
     return true;
   }
   // -----------------------------------------------------------------------------
-  //! Make mesh on an adge using assigned 1d hyp or defaut nb of segments
+  //! Make mesh on an edge using assigned 1d hyp or default nb of segments
   bool ComputeCircularEdge( SMESH_Mesh&                   aMesh,
                             const StdMeshers_FaceSidePtr& aSide )
   {
@@ -678,7 +703,7 @@ public:
     return ok;
   }
   // -----------------------------------------------------------------------------
-  //! Make mesh on an adge using assigned 1d hyp or defaut nb of segments
+  //! Make mesh on an edge using assigned 1d hyp or default nb of segments
   bool EvaluateCircularEdge(SMESH_Mesh&                  aMesh,
                             const StdMeshers_FaceSidePtr aSide,
                             MapShapeNbElems&             aResMap)
@@ -707,8 +732,8 @@ public:
   }
 protected:
   // -----------------------------------------------------------------------------
-  TNodeDistributor( int hypId, int studyId, SMESH_Gen* gen)
-    : StdMeshers_Regular_1D( hypId, studyId, gen)
+  TNodeDistributor( int hypId, SMESH_Gen* gen)
+    : StdMeshers_Regular_1D( hypId, gen)
   {
   }
   // -----------------------------------------------------------------------------
@@ -726,19 +751,19 @@ protected:
  * \brief Allow algo to do something after persistent restoration
  * \param subMesh - restored submesh
  *
- * call markEdgeAsComputedByMe()
+ * call TEdgeMarker::markEdge()
  */
 //=======================================================================
 
 void StdMeshers_RadialQuadrangle_1D2D::SubmeshRestored(SMESH_subMesh* faceSubMesh)
 {
-  // if ( !faceSubMesh->IsEmpty() )
-  // {
-  //   for ( TopExp_Explorer e( faceSubMesh->GetSubShape(), TopAbs_EDGE ); e.More(); e.Next() )
-  //   {
-  //     markEdgeAsComputedByMe( TopoDS::Edge( e.Current() ), faceSubMesh );
-  //   }
-  // }
+  if ( !faceSubMesh->IsEmpty() )
+  {
+    for ( TopExp_Explorer e( faceSubMesh->GetSubShape(), TopAbs_EDGE ); e.More(); e.Next() )
+    {
+      TEdgeMarker::markEdge( TopoDS::Edge( e.Current() ), faceSubMesh );
+    }
+  }
 }
 
 //=======================================================================
@@ -755,19 +780,22 @@ bool StdMeshers_RadialQuadrangle_1D2D::Compute(SMESH_Mesh&         aMesh,
   StdMeshers_Quadrangle_2D::myCheckOri   = false;
   StdMeshers_Quadrangle_2D::myQuadList.clear();
 
+  myHelper->SetSubShape( aShape );
+  myHelper->SetElementsOnShape( true );
+
   StdMeshers_FaceSidePtr circSide, linSide1, linSide2;
-  int nbSides = analyseFace( aShape, &aMesh, circSide, linSide1, linSide2 );
+  int nbSides = analyseFace( aShape, &aMesh, circSide, linSide1, linSide2, myHelper );
   if( nbSides > 3 || nbSides < 1 )
     return error("The face must be a full ellipse or a part of ellipse (i.e. the number "
                  "of edges is less or equal to 3 and one of them is an ellipse curve)");
 
   // get not yet computed EDGEs
-  // list< TopoDS_Edge > emptyEdges;
-  // for ( TopExp_Explorer e( aShape, TopAbs_EDGE ); e.More(); e.Next() )
-  // {
-  //   if ( aMesh.GetSubMesh( e.Current() )->IsEmpty() )
-  //     emptyEdges.push_back( TopoDS::Edge( e.Current() ));
-  // }
+  list< TopoDS_Edge > emptyEdges;
+  for ( TopExp_Explorer e( aShape, TopAbs_EDGE ); e.More(); e.Next() )
+  {
+    if ( aMesh.GetSubMesh( e.Current() )->IsEmpty() )
+      emptyEdges.push_back( TopoDS::Edge( e.Current() ));
+  }
 
   TNodeDistributor* algo1d = TNodeDistributor::GetDistributor(aMesh);
 
@@ -779,7 +807,6 @@ bool StdMeshers_RadialQuadrangle_1D2D::Compute(SMESH_Mesh&         aMesh,
   Handle(Geom_Surface) S = BRep_Tool::Surface(F);
 
   myHelper->IsQuadraticSubMesh( aShape );
-  myHelper->SetElementsOnShape( true );
 
   vector< double > layerPositions; // [0,1]
 
@@ -793,7 +820,7 @@ bool StdMeshers_RadialQuadrangle_1D2D::Compute(SMESH_Mesh&         aMesh,
     TopoDS_Edge linEdge = makeEdgeToCenter( circSide, F, circNode );
 
     StdMeshers_FaceSidePtr tmpSide =
-      StdMeshers_FaceSide::New( F, linEdge, &aMesh, /*isFrw=*/true, /*skipMedium=*/true );
+      StdMeshers_FaceSide::New( F, linEdge, &aMesh, /*isFrw=*/true, /*skipMedium=*/true, myHelper );
 
     if ( !computeLayerPositions( tmpSide, layerPositions ))
       return false;
@@ -837,7 +864,7 @@ bool StdMeshers_RadialQuadrangle_1D2D::Compute(SMESH_Mesh&         aMesh,
       isVIn0Shared = vIn0.IsSame( circSide->FirstVertex( iE ));
 
     linSide1 = StdMeshers_FaceSide::New( F, edges, &aMesh,
-                                         /*isFrw=*/isVIn0Shared, /*skipMedium=*/true );
+                                         /*isFrw=*/isVIn0Shared, /*skipMedium=*/true, myHelper );
 
     int nbMeshedEdges;
     if ( !computeLayerPositions( linSide1, layerPositions, &nbMeshedEdges ))
@@ -941,9 +968,9 @@ bool StdMeshers_RadialQuadrangle_1D2D::Compute(SMESH_Mesh&         aMesh,
     centerUV   = nodes2.back().UV();
   }
 
-  // list< TopoDS_Edge >::iterator ee = emptyEdges.begin();
-  // for ( ; ee != emptyEdges.end(); ++ee )
-  //   markEdgeAsComputedByMe( *ee, aMesh.GetSubMesh( F ));
+  list< TopoDS_Edge >::iterator ee = emptyEdges.begin();
+  for ( ; ee != emptyEdges.end(); ++ee )
+    TEdgeMarker::markEdge( *ee, aMesh.GetSubMesh( F ));
 
   circSide->GetUVPtStruct(); // let sides take into account just computed nodes
   linSide1->GetUVPtStruct();
@@ -1087,7 +1114,7 @@ bool StdMeshers_RadialQuadrangle_1D2D::Evaluate(SMESH_Mesh&         aMesh,
   TNodeDistributor* algo1d = TNodeDistributor::GetDistributor(aMesh);
 
   StdMeshers_FaceSidePtr circSide, linSide1, linSide2;
-  int nbSides = analyseFace( aShape, &aMesh, circSide, linSide1, linSide2 );
+  int nbSides = analyseFace( aShape, &aMesh, circSide, linSide1, linSide2, myHelper );
   if( nbSides > 3 || nbSides < 1 )
     return false;
 
@@ -1105,7 +1132,7 @@ bool StdMeshers_RadialQuadrangle_1D2D::Evaluate(SMESH_Mesh&         aMesh,
     TopoDS_Edge linEdge = makeEdgeToCenter( circSide, F, circNode );
 
     StdMeshers_FaceSidePtr tmpSide =
-      StdMeshers_FaceSide::New( F, linEdge, &aMesh, /*isFrw=*/true, /*skipMedium=*/true );
+      StdMeshers_FaceSide::New( F, linEdge, &aMesh, /*isFrw=*/true, /*skipMedium=*/true, myHelper );
 
     if ( !computeLayerPositions( tmpSide, layerPositions ))
       return false;
@@ -1202,7 +1229,7 @@ bool StdMeshers_RadialQuadrangle_1D2D::IsApplicable( const TopoDS_Shape & aShape
   for (TopExp_Explorer exp( aShape, TopAbs_FACE ); exp.More(); exp.Next(), ++nbFoundFaces )
   {
     StdMeshers_FaceSidePtr circSide, linSide1, linSide2;
-    int nbSides = analyseFace( aShape, NULL, circSide, linSide1, linSide2 );
+    int nbSides = analyseFace( exp.Current(), NULL, circSide, linSide1, linSide2, NULL );
     bool ok = ( 0 < nbSides && nbSides <= 3 &&
                 isCornerInsideCircle( circSide, linSide1, linSide2 ));
     if( toCheckAll  && !ok ) return false;