-// 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"
#include "SMESH_Algo.hxx"
#include "SMESH_MesherHelper.hxx"
+#include "SMESH_Group.hxx"
+#include "SMESHDS_GroupBase.hxx"
#include <IntAna_IntConicQuad.hxx>
#include <IntAna_Quadric.hxx>
#include <TopoDS.hxx>
#include <gp_Lin.hxx>
#include <gp_Pln.hxx>
+#include "utilities.h"
+#include <string>
#include <numeric>
+#include <limits>
using namespace std;
// 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 )
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);
+ }
+ }
+ }
+
}
//================================================================================
// find and remove coincided faces of merged pyramids
vector< const SMDS_MeshElement* > inverseElems
- // copy inverse elements to avoid iteration on changing container
+ // copy inverse elements to avoid iteration on changing container
( TStdElemIterator( CommonNode->GetInverseElementIterator(SMDSAbs_Face)), itEnd);
for ( unsigned i = 0; i < inverseElems.size(); ++i )
{
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)
{
return false;
}
-
//=======================================================================
//function : HasIntersection
//purpose : Auxilare for CheckIntersection()
gp_Ax1 line( P, gp_Vec(P,PC));
vector< const SMDS_MeshElement* > suspectElems;
searcher->GetElementsNearLine( line, SMDSAbs_Face, suspectElems);
-
+
for ( int i = 0; i < suspectElems.size(); ++i )
{
const SMDS_MeshElement* face = suspectElems[i];
if ( face == NotCheckedFace ) continue;
Handle(TColgp_HSequenceOfPnt) aContour = new TColgp_HSequenceOfPnt;
- for ( int i = 0; i < face->NbCornerNodes(); ++i )
+ for ( int i = 0; i < face->NbCornerNodes(); ++i )
aContour->Append( SMESH_TNodeXYZ( face->GetNode(i) ));
if( HasIntersection(P, PC, Pres, aContour) ) {
res = true;
//=======================================================================
//function : Compute
-//purpose :
+//purpose :
//=======================================================================
-bool StdMeshers_QuadToTriaAdaptor::Compute(SMESH_Mesh& aMesh,
- const TopoDS_Shape& aShape,
- SMESH_ProxyMesh* aProxyMesh)
+bool StdMeshers_QuadToTriaAdaptor::Compute(SMESH_Mesh& aMesh,
+ const TopoDS_Shape& aShape,
+ SMESH_ProxyMesh* aProxyMesh)
{
SMESH_ProxyMesh::setMesh( aMesh );
aShape.ShapeType() != TopAbs_SHELL )
return false;
+ myShape = aShape;
+
vector<const SMDS_MeshElement*> myPyramids;
SMESHDS_Mesh * meshDS = aMesh.GetMeshDS();
{
bool isRev = false;
if ( helper.NbAncestors( aShapeFace, aMesh, aShape.ShapeType() ) > 1 )
- isRev = SMESH_Algo::IsReversedSubMesh( TopoDS::Face(aShapeFace), meshDS );
+ isRev = helper.IsReversedSubMesh( TopoDS::Face(aShapeFace) );
SMDS_ElemIteratorPtr iteratorElem = aSubMeshDSFace->GetElements();
while ( iteratorElem->more() ) // loop on elements on a geometrical face
if ( aMesh.NbQuadrangles() < 1 )
return false;
+ // find if there is a group of faces identified as skin faces, with normal going outside the volume
+ std::string groupName = "skinFaces";
+ SMESHDS_GroupBase* groupDS = 0;
+ SMESH_Mesh::GroupIteratorPtr groupIt = aMesh.GetGroups();
+ while ( groupIt->more() )
+ {
+ groupDS = 0;
+ SMESH_Group * group = groupIt->next();
+ if ( !group ) continue;
+ groupDS = group->GetGroupDS();
+ if ( !groupDS || groupDS->IsEmpty() )
+ {
+ groupDS = 0;
+ continue;
+ }
+ if (groupDS->GetType() != SMDSAbs_Face)
+ {
+ groupDS = 0;
+ continue;
+ }
+ std::string grpName = group->GetName();
+ if (grpName == groupName)
+ {
+ MESSAGE("group skinFaces provided");
+ break;
+ }
+ else
+ groupDS = 0;
+ }
+
vector<const SMDS_MeshElement*> myPyramids;
SMESH_MesherHelper helper(aMesh);
helper.IsQuadraticSubMesh(aMesh.GetShapeToMesh());
SMESH_ProxyMesh::SubMesh* prxSubMesh = getProxySubMesh();
SMDS_FaceIteratorPtr fIt = meshDS->facesIterator(/*idInceasingOrder=*/true);
- while( fIt->more())
+ while( fIt->more())
{
const SMDS_MeshElement* face = fIt->next();
if ( !face ) continue;
continue;
}
- // Case of non-degenerated quadrangle
+ // Case of non-degenerated quadrangle
// Find pyramid peak
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
}
}
+ // if the face belong to the group of skinFaces, do not build a pyramid outside
+ if (groupDS && groupDS->Contains(face))
+ intersected[0] = false;
+
// Create one or two pyramids
for ( int isRev = 0; isRev < 2; ++isRev )
for(k=0; k<4 && !hasInt; k++) {
gp_Vec Vtmp(PsI[k],PsI[4]);
gp_Pnt Pshift = PsI[k].XYZ() + Vtmp.XYZ() * 0.01; // base node moved a bit to apex
- hasInt =
+ hasInt =
( HasIntersection3( Pshift, PsI[4], Pint, PsJ[0], PsJ[1], PsJ[4]) ||
HasIntersection3( Pshift, PsI[4], Pint, PsJ[1], PsJ[2], PsJ[4]) ||
HasIntersection3( Pshift, PsI[4], Pint, PsJ[2], PsJ[3], PsJ[4]) ||
for(k=0; k<4 && !hasInt; k++) {
gp_Vec Vtmp(PsJ[k],PsJ[4]);
gp_Pnt Pshift = PsJ[k].XYZ() + Vtmp.XYZ() * 0.01;
- hasInt =
+ hasInt =
( HasIntersection3( Pshift, PsJ[4], Pint, PsI[0], PsI[1], PsI[4]) ||
HasIntersection3( Pshift, PsJ[4], Pint, PsI[1], PsI[2], PsI[4]) ||
HasIntersection3( Pshift, PsJ[4], Pint, PsI[2], PsI[3], PsI[4]) ||
PCi += PsI[k].XYZ();
PCj += PsJ[k].XYZ();
}
- PCi /= 4; PCj /= 4;
+ PCi /= 4; PCj /= 4;
gp_Vec VN1(PCi,PsI[4]);
gp_Vec VN2(PCj,PsJ[4]);
gp_Vec VI1(PCi,Pint);
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;
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() )
{
return true;
}
-