Salome HOME
IPAL22856 2D quadrangle mesher of reduced type works wrong
[modules/smesh.git] / src / StdMeshers / StdMeshers_QuadToTriaAdaptor.cxx
index c8bc5d9dad83eb67d7b3478da1782f4af7e7e0bd..d9907cba9c5355dc1ca3c6320bc2532cd9fb9378 100644 (file)
@@ -1,27 +1,27 @@
-//  Copyright (C) 2007-2010  CEA/DEN, EDF R&D, OPEN CASCADE
+// Copyright (C) 2007-2012  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
-//  License as published by the Free Software Foundation; either
-//  version 2.1 of the License.
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License.
 //
-//  This library is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-//  Lesser General Public License for more details.
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
 //
-//  You should have received a copy of the GNU Lesser General Public
-//  License along with this library; if not, write to the Free Software
-//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 //
-//  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
 //
 
 // File      : StdMeshers_QuadToTriaAdaptor.cxx
 // Module    : SMESH
 // Created   : Wen May 07 16:37:07 2008
 // Author    : Sergey KUUL (skl)
-//
+
 #include "StdMeshers_QuadToTriaAdaptor.hxx"
 
 #include "SMDS_SetIterator.hxx"
@@ -40,6 +40,7 @@
 #include <gp_Pln.hxx>
 
 #include <numeric>
+#include <limits>
 
 using namespace std;
 
@@ -110,7 +111,7 @@ namespace
 
     // Check angle between normals
     double angle = nI.Angle( nJ );
-    bool tooClose = ( angle < 15 * PI180 );
+    bool tooClose = ( angle < 15. * M_PI / 180. );
 
     // Check if pyramids collide
     if ( !tooClose && baI * baJ > 0 )
@@ -175,6 +176,79 @@ namespace
 
     return tooClose;
   }
+
+  //================================================================================
+  /*!
+   * \brief Move medium nodes of merged quadratic pyramids
+   */
+  //================================================================================
+
+  void UpdateQuadraticPyramids(const set<const SMDS_MeshNode*>& commonApex,
+                               SMESHDS_Mesh*                    meshDS)
+  {
+    typedef SMDS_StdIterator< const SMDS_MeshElement*, SMDS_ElemIteratorPtr > TStdElemIterator;
+    TStdElemIterator itEnd;
+
+    // shift of node index to get medium nodes between the 4 base nodes and the apex
+    const int base2MediumShift = 9;
+
+    set<const SMDS_MeshNode*>::const_iterator nIt = commonApex.begin();
+    for ( ; nIt != commonApex.end(); ++nIt )
+    {
+      SMESH_TNodeXYZ apex( *nIt );
+
+      vector< const SMDS_MeshElement* > pyrams // pyramids sharing the apex node
+        ( TStdElemIterator( apex._node->GetInverseElementIterator( SMDSAbs_Volume )), itEnd );
+
+      // Select medium nodes to keep and medium nodes to remove
+
+      typedef map < const SMDS_MeshNode*, const SMDS_MeshNode*, TIDCompare > TN2NMap;
+      TN2NMap base2medium; // to keep
+      vector< const SMDS_MeshNode* > nodesToRemove;
+
+      for ( unsigned i = 0; i < pyrams.size(); ++i )
+        for ( int baseIndex = 0; baseIndex < PYRAM_APEX; ++baseIndex )
+        {
+          SMESH_TNodeXYZ         base = pyrams[i]->GetNode( baseIndex );
+          const SMDS_MeshNode* medium = pyrams[i]->GetNode( baseIndex + base2MediumShift );
+          TN2NMap::iterator b2m = base2medium.insert( make_pair( base._node, medium )).first;
+          if ( b2m->second != medium )
+          {
+            nodesToRemove.push_back( medium );
+          }
+          else
+          {
+            // move the kept medium node
+            gp_XYZ newXYZ = 0.5 * ( apex + base );
+            meshDS->MoveNode( medium, newXYZ.X(), newXYZ.Y(), newXYZ.Z() );
+          }
+        }
+
+      // Within pyramids, replace nodes to remove by nodes to keep  
+
+      for ( unsigned i = 0; i < pyrams.size(); ++i )
+      {
+        vector< const SMDS_MeshNode* > nodes( pyrams[i]->begin_nodes(),
+                                              pyrams[i]->end_nodes() );
+        for ( int baseIndex = 0; baseIndex < PYRAM_APEX; ++baseIndex )
+        {
+          const SMDS_MeshNode* base = pyrams[i]->GetNode( baseIndex );
+          nodes[ baseIndex + base2MediumShift ] = base2medium[ base ];
+        }
+        meshDS->ChangeElementNodes( pyrams[i], &nodes[0], nodes.size());
+      }
+
+      // Remove the replaced nodes
+
+      if ( !nodesToRemove.empty() )
+      {
+        SMESHDS_SubMesh * sm = meshDS->MeshElements( nodesToRemove[0]->getshapeId() );
+        for ( unsigned i = 0; i < nodesToRemove.size(); ++i )
+          meshDS->RemoveFreeNode( nodesToRemove[i], sm, /*fromGroups=*/false);
+      }
+    }
+  }
+
 }
 
 //================================================================================
@@ -305,37 +379,41 @@ StdMeshers_QuadToTriaAdaptor::~StdMeshers_QuadToTriaAdaptor()
   myElemSearcher=0;
 }
 
-
 //=======================================================================
 //function : FindBestPoint
 //purpose  : Return a point P laying on the line (PC,V) so that triangle
 //           (P, P1, P2) to be equilateral as much as possible
 //           V - normal to (P1,P2,PC)
 //=======================================================================
+
 static gp_Pnt FindBestPoint(const gp_Pnt& P1, const gp_Pnt& P2,
                             const gp_Pnt& PC, const gp_Vec& V)
 {
-  double a = P1.Distance(P2);
-  double b = P1.Distance(PC);
-  double c = P2.Distance(PC);
+  gp_Pnt Pbest = PC;
+  const double a = P1.Distance(P2);
+  const double b = P1.Distance(PC);
+  const double c = P2.Distance(PC);
   if( a < (b+c)/2 )
-    return PC;
+    return Pbest;
   else {
     // find shift along V in order a to became equal to (b+c)/2
-    double shift = sqrt( a*a + (b*b-c*c)*(b*b-c*c)/16/a/a - (b*b+c*c)/2 );
-    gp_Dir aDir(V);
-    gp_Pnt Pbest = PC.XYZ() + aDir.XYZ() * shift;
-    return Pbest;
+    const double Vsize = V.Magnitude();
+    if ( fabs( Vsize ) > std::numeric_limits<double>::min() )
+    {
+      const double shift = sqrt( a*a + (b*b-c*c)*(b*b-c*c)/16/a/a - (b*b+c*c)/2 );
+      Pbest.ChangeCoord() += shift * V.XYZ() / Vsize;
+    }
   }
+  return Pbest;
 }
 
-
 //=======================================================================
 //function : HasIntersection3
 //purpose  : Auxilare for HasIntersection()
 //           find intersection point between triangle (P1,P2,P3)
 //           and segment [PC,P]
 //=======================================================================
+
 static bool HasIntersection3(const gp_Pnt& P, const gp_Pnt& PC, gp_Pnt& Pint,
                              const gp_Pnt& P1, const gp_Pnt& P2, const gp_Pnt& P3)
 {
@@ -406,7 +484,6 @@ static bool HasIntersection3(const gp_Pnt& P, const gp_Pnt& PC, gp_Pnt& Pint,
   return false;
 }
 
-
 //=======================================================================
 //function : HasIntersection
 //purpose  : Auxilare for CheckIntersection()
@@ -937,10 +1014,12 @@ bool StdMeshers_QuadToTriaAdaptor::Compute(SMESH_Mesh& aMesh)
     PCbest /= 4;
 
     double height = PC.Distance(PCbest); // pyramid height to precise
-    if(height<1.e-6) {
+    if ( height < 1.e-6 ) {
       // create new PCbest using a bit shift along VNorm
       PCbest = PC.XYZ() + VNorm.XYZ() * 0.001;
       height = PC.Distance(PCbest);
+      if ( height < std::numeric_limits<double>::min() )
+        return false; // batterfly element
     }
 
     // Restrict pyramid height by intersection with other faces
@@ -1141,8 +1220,8 @@ bool StdMeshers_QuadToTriaAdaptor::Compute2ndPart(SMESH_Mesh&
             gp_Vec VI2(PCj,Pint);
             double ang1 = fabs(VN1.Angle(VI1));
             double ang2 = fabs(VN2.Angle(VI2));
-            double coef1 = 0.5 - (( ang1<PI/3 ) ? cos(ang1)*0.25 : 0 );
-            double coef2 = 0.5 - (( ang2<PI/3 ) ? cos(ang2)*0.25 : 0 ); // cos(ang2) ?
+            double coef1 = 0.5 - (( ang1 < M_PI/3. ) ? cos(ang1)*0.25 : 0 );
+            double coef2 = 0.5 - (( ang2 < M_PI/3. ) ? cos(ang2)*0.25 : 0 ); // cos(ang2) ?
 //             double coef2 = 0.5;
 //             if(ang2<PI/3)
 //               coef2 -= cos(ang1)*0.25;
@@ -1173,6 +1252,10 @@ bool StdMeshers_QuadToTriaAdaptor::Compute2ndPart(SMESH_Mesh&
       meshDS->MoveNode( *n, (*n)->X(), (*n)->Y(), (*n)->Z() );
   }
 
+  // move medium nodes of merged quadratic pyramids
+  if ( myPyramids[0]->IsQuadratic() )
+    UpdateQuadraticPyramids( nodesToMove, GetMeshDS() );
+
   // erase removed triangles from the proxy mesh
   if ( !myRemovedTrias.empty() )
   {
@@ -1202,4 +1285,3 @@ bool StdMeshers_QuadToTriaAdaptor::Compute2ndPart(SMESH_Mesh&
 
   return true;
 }
-