Salome HOME
IPAL54425: Quadrangle mapping fails on a quadrangle face with a seam
authoreap <eap@opencascade.com>
Mon, 5 Aug 2019 17:02:26 +0000 (20:02 +0300)
committereap <eap@opencascade.com>
Mon, 5 Aug 2019 17:02:26 +0000 (20:02 +0300)
  Issue reported in https://www.salome-platform.org/forum/forum_10/984373499

+
1) Fix a bug in Python dump
2) Expose corners in Quadrangle Param gui

resources/StdMeshers.xml.in
src/SMESH/SMESH_MesherHelper.hxx
src/SMESH_I/SMESH_2smeshpy.cxx
src/StdMeshers/StdMeshers_Hexa_3D.cxx
src/StdMeshers/StdMeshers_Hexa_3D.hxx
src/StdMeshers/StdMeshers_Quadrangle_2D.cxx
src/StdMeshersGUI/StdMeshersGUI_QuadrangleParamWdg.cxx
src/StdMeshersGUI/StdMeshersGUI_QuadrangleParamWdg.h
src/StdMeshersGUI/StdMeshersGUI_SubShapeSelectorWdg.h
src/StdMeshersGUI/StdMeshers_msg_en.ts

index 7d480e6906ea4c35cc1baefbf3bc271909fd2c9b..a765bbc7aee1a58f85861046dd8ed36da1e95439 100644 (file)
                dim      ="2">
       <python-wrap>
         <algo>Quadrangle_2D=Quadrangle(algo=smeshBuilder.QUADRANGLE)</algo>
-        <hypo>QuadrangleParams=QuadrangleParameters(SetQuadType(),SetTriaVertex(),SetEnforcedNodes(1),SetEnforcedNodes(2))</hypo>
+        <hypo>QuadrangleParams=QuadrangleParameters(SetQuadType(),SetTriaVertex(),SetEnforcedNodes(1),SetEnforcedNodes(2),SetCorners())</hypo>
         <hypo>ViscousLayers2D=ViscousLayers2D(SetTotalThickness(),SetNumberLayers(),SetStretchFactor(),SetIgnoreEdges())</hypo>
       </python-wrap>
     </algorithm>
index 08d504ebc846b999fc680e913bd48a1d163aedd8..e0a4eb7aae6dc6c56a2ff2a689aa93101a4dae10 100644 (file)
@@ -635,6 +635,10 @@ public:
    *  \retval int - 1 for U, 2 for V direction
    */
   int GetPeriodicIndex() const { return myParIndex; }
+  /*!
+   * \brief Return period in given direction [1,2]
+   */
+  double GetPeriod(int perioIndex) const { return myPar2[ perioIndex-1 ] - myPar1[ perioIndex-1 ]; }
   /*!
    * \brief Return an alternative parameter for a node on seam
    */
index 45540d510a4f8157a2df1b610317ab85c87aeb4a..b22af73ebdb34d756c8a7364e697759a19b80f68 100644 (file)
@@ -1971,7 +1971,7 @@ void _pyMesh::Process( const Handle(_pyCommand)& theCommand )
       if ( !obj->CanClear() )
         allGroupsRemoved = false;
     }
-    if ( nbGroupsBefore == myGroups.size() ) // no new _pyGroup created
+    if ( nbGroupsBefore == myGroups.size() && !obj.IsNull() ) // no new _pyGroup created
       obj->AddProcessedCmd( theCommand ); // to clear theCommand if all groups are removed
 
     if ( !allGroupsRemoved && !theGen->IsToKeepAllCommands() )
index 7dadb9c2503f056e3c603a3e95979acf9f819678..86f77bbd1a83d23f0db4d4d9ea1123b5f90178a6 100644 (file)
@@ -77,6 +77,7 @@ StdMeshers_Hexa_3D::StdMeshers_Hexa_3D(int hypId, SMESH_Gen * gen)
   _shapeType = (1 << TopAbs_SHELL) | (1 << TopAbs_SOLID);       // 1 bit /shape type
   _requireShape = false;
   _compatibleHypothesis.push_back("ViscousLayers");
+  _quadAlgo = new StdMeshers_Quadrangle_2D( gen->GetANewId(), _gen );
 }
 
 //=============================================================================
@@ -87,6 +88,8 @@ StdMeshers_Hexa_3D::StdMeshers_Hexa_3D(int hypId, SMESH_Gen * gen)
 
 StdMeshers_Hexa_3D::~StdMeshers_Hexa_3D()
 {
+  delete _quadAlgo;
+  _quadAlgo = 0;
 }
 
 //=============================================================================
@@ -231,7 +234,7 @@ namespace
     for ( int i = 1; i < 6; ++i )
     {
       if ( !quad[i] ) continue;
-      for ( unsigned iS = 0; iS < quad[i]->side.size(); ++iS )
+      for ( size_t iS = 0; iS < quad[i]->side.size(); ++iS )
       {
         const StdMeshers_FaceSidePtr side2 = quad[i]->side[iS];
         if (( side->FirstVertex().IsSame( side2->FirstVertex() ) ||
@@ -244,9 +247,9 @@ namespace
           if ( iS != Q_BOTTOM )
           {
             vector< FaceQuadStruct::Side > newSides;
-            for ( unsigned j = iS; j < quad[i]->side.size(); ++j )
+            for ( size_t j = iS; j < quad[i]->side.size(); ++j )
               newSides.push_back( quad[i]->side[j] );
-            for ( unsigned j = 0; j < iS; ++j )
+            for ( size_t j = 0; j < iS; ++j )
               newSides.push_back( quad[i]->side[j] );
             quad[i]->side.swap( newSides );
           }
@@ -363,7 +366,7 @@ bool StdMeshers_Hexa_3D::Compute(SMESH_Mesh &         aMesh,
   if ( exp.Next(), exp.More() )
     return error(COMPERR_BAD_SHAPE, "More than one SHELL in the geometry");
 
-  TopTools_IndexedMapOfShape FF;
+  TopTools_IndexedMapOfShape FF, EE;
   TopExp::MapShapes( aShape, TopAbs_FACE, FF);
   if ( FF.Extent() != 6)
   {
@@ -375,14 +378,23 @@ bool StdMeshers_Hexa_3D::Compute(SMESH_Mesh &         aMesh,
 
   // Find sides of a cube
   // ---------------------
-  
+
+  // tool creating quadratic elements if needed
+  SMESH_MesherHelper helper (aMesh);
+  _quadraticMesh = helper.IsQuadraticSubMesh(aShape);
+
+  TopExp::MapShapes( aShape, TopAbs_EDGE, EE );
+  SMESH_MesherHelper* faceHelper = ( EE.Size() == 12 ) ? 0 : &helper;
+
   FaceQuadStructPtr quad[ 6 ];
-  StdMeshers_Quadrangle_2D quadAlgo( _gen->GetANewId(), _gen);
   for ( int i = 0; i < 6; ++i )
   {
-    if ( !( quad[i] = FaceQuadStructPtr( quadAlgo.CheckNbEdges( aMesh, FF( i+1 ),
-                                                                /*considerMesh=*/true))))
-      return error( quadAlgo.GetComputeError() );
+    if ( faceHelper )
+      faceHelper->SetSubShape( FF( i+1 ));
+    if ( !( quad[i] = FaceQuadStructPtr( _quadAlgo->CheckNbEdges( aMesh, FF( i+1 ),
+                                                                  /*considerMesh=*/true,
+                                                                  faceHelper))))
+      return error( _quadAlgo->GetComputeError() );
     if ( quad[i]->side.size() != 4 )
       return error( COMPERR_BAD_SHAPE, "Not a quadrangular box side" );
   }
@@ -437,10 +449,6 @@ bool StdMeshers_Hexa_3D::Compute(SMESH_Mesh &         aMesh,
   // Check presence of regular grid mesh on FACEs of the cube
   // ------------------------------------------------------------
 
-  // tool creating quadratic elements if needed
-  SMESH_MesherHelper helper (aMesh);
-  _quadraticMesh = helper.IsQuadraticSubMesh(aShape);
-
   for ( int i = 0; i < 6; ++i )
   {
     const TopoDS_Face& F = aCubeSide[i]._quad->face;
@@ -513,8 +521,8 @@ bool StdMeshers_Hexa_3D::Compute(SMESH_Mesh &         aMesh,
 
   if ( proxymesh )
     for ( int i = 0; i < 6; ++i )
-      for ( unsigned j = 0; j < aCubeSide[i]._columns.size(); ++j)
-        for ( unsigned k = 0; k < aCubeSide[i]._columns[j].size(); ++k)
+      for ( size_t j = 0; j < aCubeSide[i]._columns.size(); ++j)
+        for ( size_t k = 0; k < aCubeSide[i]._columns[j].size(); ++k)
         {
           const SMDS_MeshNode* & n = aCubeSide[i]._columns[j][k];
           n = proxymesh->GetProxyNode( n );
index 49046302e4b22ba13dccd41cf13931e76f988c04..00ff85cf543d681917087219f19c85c8864c0763 100644 (file)
@@ -34,8 +34,9 @@
 #include "SMESH_Algo.hxx"
 
 
-class StdMeshers_ViscousLayers;
 class SMESH_MesherHelper;
+class StdMeshers_Quadrangle_2D;
+class StdMeshers_ViscousLayers;
 
 class STDMESHERS_EXPORT StdMeshers_Hexa_3D : public SMESH_3D_Algo
 {
@@ -63,6 +64,7 @@ public:
  protected:
 
   const StdMeshers_ViscousLayers* _viscousLayersHyp;
+  StdMeshers_Quadrangle_2D*       _quadAlgo;
 };
 
 #endif
index 6173866f4b9ebd7d8c2ea74a803edc9c57494321..6f087bfa261c985890545cb2c9b22f634e173fd7 100644 (file)
@@ -51,6 +51,7 @@
 #include <Geom_Surface.hxx>
 #include <NCollection_DefineArray2.hxx>
 #include <Precision.hxx>
+#include <ShapeAnalysis.hxx>
 #include <TColStd_SequenceOfInteger.hxx>
 #include <TColStd_SequenceOfReal.hxx>
 #include <TColgp_SequenceOfXY.hxx>
@@ -1221,7 +1222,9 @@ namespace
    *  \param [in] theNbCorners - the required number of sides, 3 or 4
    *  \param [in] theConsiderMesh - to considered only meshed VERTEXes
    *  \param [in] theFaceSide - the FACE EDGEs
+   *  \param [in] theFixedVertices - VERTEXes to be used as corners
    *  \param [out] theVertices - the found corner vertices
+   *  \param [out] theHaveConcaveVertices - return if there are concave vertices
    */
   //================================================================================
 
@@ -1432,6 +1435,39 @@ namespace
     return;
   }
 
+  //================================================================================
+  /*!
+   * \brief Remove a seam and degenerated edge from a wire if the shape is
+   *        a quadrangle with a seam inside.
+   */
+  //================================================================================
+
+  bool removeInternalSeam( std::list<TopoDS_Edge>& theWire,
+                           SMESH_MesherHelper&     theHelper)
+  {
+    if ( !theHelper.HasRealSeam() ||
+         theHelper.NbDegeneratedEdges() != 2 ) // 1 EDGE + 1 VERTEX
+      return false;
+
+    typedef std::list<TopoDS_Edge>::iterator TEdgeIter;
+    std::vector< TEdgeIter > edgesToRemove;
+    edgesToRemove.reserve( 5 );
+    for ( TEdgeIter eIt = theWire.begin(); eIt != theWire.end(); ++eIt )
+    {
+      int eID = theHelper.ShapeToIndex( *eIt );
+      if ( theHelper.IsRealSeam( eID ) || theHelper.IsDegenShape( eID ))
+        edgesToRemove.push_back( eIt );
+    }
+
+    if ( theWire.size() - edgesToRemove.size() < 4 )
+      return false; // cone e.g.
+
+    for ( size_t i = 0; i < edgesToRemove.size(); ++i )
+      theWire.erase( edgesToRemove[ i ]);
+
+    return true;
+  }
+
 } // namespace
 
 //================================================================================
@@ -1462,6 +1498,9 @@ int StdMeshers_Quadrangle_2D::getCorners(const TopoDS_Face&          theFace,
   if ( myHelper )
     helper.CopySubShapeInfo( *myHelper );
 
+  if ( removeInternalSeam( theWire, helper ))
+    theNbDegenEdges = 1;
+
   StdMeshers_FaceSide faceSide( theFace, theWire, &theMesh,
                                 /*isFwd=*/true, /*skipMedium=*/true, &helper );
 
@@ -4774,20 +4813,35 @@ bool StdMeshers_Quadrangle_2D::check()
     default:;
     }
 
-    // if ( isBad && myHelper->HasRealSeam() )
-    // {
-    //   // detect a case where a face intersects the seam
-    //   for ( int iPar = 1; iPar < 3; ++iPar )
-    //     if ( iPar & myHelper->GetPeriodicIndex() )
-    //     {
-    //       double min = uv[0].Coord( iPar ), max = uv[0].Coord( iPar );
-    //       for ( int i = 1; i < nbN; ++i )
-    //       {
-    //         min = Min( min, uv[i].Coord( iPar ));
-    //         max = Max( max, uv[i].Coord( iPar ));
-    //       }
-    //     }
-    // }
+    if ( isBad && myHelper->HasRealSeam() )
+    {
+      // fix uv for a case where a face intersects the seam
+      for ( int iPar = 1; iPar < 3; ++iPar )
+        if ( iPar & myHelper->GetPeriodicIndex() )
+        {
+          double max = uv[0].Coord( iPar );
+          for ( int i = 1; i < nbN; ++i )
+            max = Max( max, uv[i].Coord( iPar ));
+
+          for ( int i = 0; i < nbN; ++i )
+          {
+            double par   = uv[i].Coord( iPar );
+            double shift = ShapeAnalysis::AdjustByPeriod( par, max, myHelper->GetPeriod( iPar ));
+            uv[i].SetCoord( iPar, par + shift );
+          }
+        }
+      double sign1 = getArea( uv[0], uv[1], uv[2] );
+      double sign2 = getArea( uv[0], uv[2], uv[3] );
+      if ( sign1 * sign2 < 0 )
+      {
+        sign2 = getArea( uv[1], uv[2], uv[3] );
+        sign1 = getArea( uv[1], uv[3], uv[0] );
+        if ( sign1 * sign2 < 0 )
+          continue; // this should not happen
+      }
+      isBad = ( sign1 * okSign < 0 );
+    }
+
     if ( isBad )
       badFaces.push_back ( f );
   }
index 7df2045bdd3e1dc5ee6ff39076eb7f38b35db43b..dda529a3f9218a20ae5600edb809795d869c199a 100644 (file)
@@ -55,7 +55,7 @@
 #define SPACING 6
 #define MARGIN 11
 
-enum { TAB_TRANSITION, TAB_VERTEX, TAB_ENF_POINTS };
+enum { TAB_TRANSITION, TAB_VERTEX, TAB_CORNERS, TAB_ENF_POINTS };
 
 //================================================================================
 // function : Constructor
@@ -153,11 +153,17 @@ QFrame*  StdMeshersGUI_QuadrangleParamCreator::buildFrame()
   pointsLay->addWidget( shapesGroup );
   pointsLay->addWidget( coordsGroup );
 
+  // Corners
+
+  myCornersSelWdg = new StdMeshersGUI_SubShapeSelectorWdg( fr, TopAbs_VERTEX );
+  myCornersSelWdg->layout()->setMargin( MARGIN );
+
   // Tabs
   myTabs = new QTabWidget( fr );
-  myTabs->addTab( myTypeWdg,      tr("TRANSITION"));
-  myTabs->addTab( myVertexSelWdg, tr("SMESH_BASE_VERTEX"));
-  myTabs->addTab( pointsFrame,    tr("ENF_NODES"));
+  myTabs->addTab( myTypeWdg,       tr("TRANSITION"));
+  myTabs->addTab( myVertexSelWdg,  tr("SMESH_BASE_VERTEX"));
+  myTabs->addTab( myCornersSelWdg, tr("CORNERS"));
+  myTabs->addTab( pointsFrame,     tr("ENF_NODES"));
 
   lay->addWidget( myTabs, row, 0, 2, 3 );
 
@@ -196,6 +202,7 @@ void StdMeshersGUI_QuadrangleParamCreator::retrieveParams() const
   if ( anEntry.isEmpty() )
     anEntry = h->GetObjectEntry();
   myVertexSelWdg->SetGeomShapeEntry(anEntry,aMainEntry);
+  myCornersSelWdg->SetGeomShapeEntry(anEntry,aMainEntry);
 
   if ( !isCreation())
   {
@@ -211,6 +218,10 @@ void StdMeshersGUI_QuadrangleParamCreator::retrieveParams() const
       myVertexSelWdg->SetListOfIDs(aVec);
     }
 
+    // corners
+    SMESH::long_array_var aVec = h->GetCorners();
+    myCornersSelWdg->SetListOfIDs( aVec );
+
     // enforced nodes
     GEOM::ListOfGO_var     shapes;
     SMESH::nodes_array_var points;
@@ -265,6 +276,9 @@ QString  StdMeshersGUI_QuadrangleParamCreator::storeParams() const
     h->SetTriaVertex( -1 );
   }
 
+  // corners
+  h->SetCorners( myCornersSelWdg->GetListOfIDs() );
+
   // enfored nodes
 
   GEOM::ListOfGO_var goList = new GEOM::ListOfGO;
@@ -408,6 +422,7 @@ void StdMeshersGUI_QuadrangleParamCreator::onSelectionChanged()
 void StdMeshersGUI_QuadrangleParamCreator::onTabChanged(int i)
 {
   myVertexSelWdg->ShowPreview( i == TAB_VERTEX );
+  myCornersSelWdg->ShowPreview( i == TAB_CORNERS );
 }
 
 //================================================================================
index 5264f1942c1c4add0eb1bfd36463f29fd2c2b65c..5aa4b74cb06bfcf0187029dfbfb7da70d24a46bd 100644 (file)
@@ -78,6 +78,7 @@ class STDMESHERSGUI_EXPORT StdMeshersGUI_QuadrangleParamCreator : public StdMesh
   QLineEdit*                         myName;
   StdMeshersGUI_QuadrangleParamWdg*  myTypeWdg;
   StdMeshersGUI_SubShapeSelectorWdg* myVertexSelWdg;
+  StdMeshersGUI_SubShapeSelectorWdg* myCornersSelWdg;
   QListWidget*                       myShapesList;
   QPushButton*                       myAddShapeBut;
   QTreeWidget*                       myCoordsTreeWdg;
index 437da33cb74513c3db8b3ced6c8d6fe21fe6483d..a3e986a88e7ce67ecb1ed1fef1c4773b68bdbf92 100644 (file)
@@ -53,7 +53,7 @@ public:
   StdMeshersGUI_SubShapeSelectorWdg( QWidget*         parent = 0,
                                      TopAbs_ShapeEnum subShType = TopAbs_EDGE,
                                      const bool       toShowList = true,
-                                     const bool       toShowActivateBtn = false);
+                                     const bool       toShowSelectBtn = false);
   ~StdMeshersGUI_SubShapeSelectorWdg();
 
   SMESH::long_array_var          GetListOfIDs();
index 91a1b3ca6d26cf31de5e5e8bef6eb3956b151ea1..351aed8f48fb3b3855b47e5536c40840a76c073c 100644 (file)
@@ -542,6 +542,10 @@ this one for this mesh/sub-mesh.</translation>
         <source>ENF_NODES</source>
         <translation>Enforced nodes</translation>
     </message>
+    <message>
+        <source>CORNERS</source>
+        <translation>Corner Vertices</translation>
+    </message>
 </context>
 <context>
     <name>StdMeshersGUI_LayerDistributionParamWdg</name>