mirror of
https://git.salome-platform.org/gitpub/modules/smesh.git
synced 2024-12-27 09:50:34 +05:00
Bug PAL8581. Implement smoothing using UV params of nodes.
This commit is contained in:
parent
67f2fc63f5
commit
92ed7cc59f
@ -32,6 +32,7 @@
|
|||||||
#include "SMDS_VolumeTool.hxx"
|
#include "SMDS_VolumeTool.hxx"
|
||||||
#include "SMDS_EdgePosition.hxx"
|
#include "SMDS_EdgePosition.hxx"
|
||||||
#include "SMDS_PolyhedralVolumeOfNodes.hxx"
|
#include "SMDS_PolyhedralVolumeOfNodes.hxx"
|
||||||
|
#include "SMDS_FacePosition.hxx"
|
||||||
|
|
||||||
#include "SMESHDS_Group.hxx"
|
#include "SMESHDS_Group.hxx"
|
||||||
#include "SMESHDS_Mesh.hxx"
|
#include "SMESHDS_Mesh.hxx"
|
||||||
@ -54,6 +55,12 @@
|
|||||||
#include <gp_Pln.hxx>
|
#include <gp_Pln.hxx>
|
||||||
#include <BRep_Tool.hxx>
|
#include <BRep_Tool.hxx>
|
||||||
#include <Geom_Curve.hxx>
|
#include <Geom_Curve.hxx>
|
||||||
|
#include <Geom_Surface.hxx>
|
||||||
|
#include <Geom2d_Curve.hxx>
|
||||||
|
#include <Extrema_GenExtPS.hxx>
|
||||||
|
#include <Extrema_POnSurf.hxx>
|
||||||
|
#include <GeomAdaptor_Surface.hxx>
|
||||||
|
#include <ElCLib.hxx>
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
@ -1287,54 +1294,70 @@ bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
|
|||||||
// connected to that node along an element edge
|
// connected to that node along an element edge
|
||||||
//=======================================================================
|
//=======================================================================
|
||||||
|
|
||||||
void laplacianSmooth(SMESHDS_Mesh * theMesh,
|
void laplacianSmooth(const SMDS_MeshNode* theNode,
|
||||||
const SMDS_MeshNode* theNode,
|
const Handle(Geom_Surface)& theSurface,
|
||||||
const set<const SMDS_MeshElement*> & theElems,
|
map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
|
||||||
const set<const SMDS_MeshNode*> & theFixedNodes)
|
|
||||||
{
|
{
|
||||||
// find surrounding nodes
|
// find surrounding nodes
|
||||||
|
|
||||||
set< const SMDS_MeshNode* > nodeSet;
|
set< const SMDS_MeshNode* > nodeSet;
|
||||||
SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator();
|
SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator();
|
||||||
while ( elemIt->more() )
|
while ( elemIt->more() )
|
||||||
{
|
{
|
||||||
const SMDS_MeshElement* elem = elemIt->next();
|
const SMDS_MeshElement* elem = elemIt->next();
|
||||||
if ( theElems.find( elem ) == theElems.end() )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (elem->IsPoly())
|
// put all nodes in array
|
||||||
continue;
|
int nbNodes = 0, iNode = 0;
|
||||||
int i = 0, iNode = 0;
|
vector< const SMDS_MeshNode*> aNodes( elem->NbNodes() );
|
||||||
const SMDS_MeshNode* aNodes [4];
|
|
||||||
SMDS_ElemIteratorPtr itN = elem->nodesIterator();
|
SMDS_ElemIteratorPtr itN = elem->nodesIterator();
|
||||||
while ( itN->more() )
|
while ( itN->more() )
|
||||||
{
|
{
|
||||||
aNodes[ i ] = static_cast<const SMDS_MeshNode*>( itN->next() );
|
aNodes[ nbNodes ] = static_cast<const SMDS_MeshNode*>( itN->next() );
|
||||||
if ( aNodes[ i ] == theNode )
|
if ( aNodes[ nbNodes ] == theNode )
|
||||||
iNode = i;
|
iNode = nbNodes; // index of theNode within aNodes
|
||||||
else
|
nbNodes++;
|
||||||
nodeSet.insert( aNodes[ i ] );
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
if ( elem->NbNodes() == 4 ) { // remove an opposite node
|
|
||||||
iNode += ( iNode < 2 ) ? 2 : -2;
|
|
||||||
nodeSet.erase( aNodes[ iNode ]);
|
|
||||||
}
|
}
|
||||||
|
// add linked nodes
|
||||||
|
int iAfter = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
|
||||||
|
nodeSet.insert( aNodes[ iAfter ]);
|
||||||
|
int iBefore = ( iNode == 0 ) ? nbNodes - 1 : iNode - 1;
|
||||||
|
nodeSet.insert( aNodes[ iBefore ]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// compute new coodrs
|
// compute new coodrs
|
||||||
|
|
||||||
double coord[] = { 0., 0., 0. };
|
double coord[] = { 0., 0., 0. };
|
||||||
set< const SMDS_MeshNode* >::iterator nodeSetIt = nodeSet.begin();
|
set< const SMDS_MeshNode* >::iterator nodeSetIt = nodeSet.begin();
|
||||||
for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
|
for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
|
||||||
const SMDS_MeshNode* node = (*nodeSetIt);
|
const SMDS_MeshNode* node = (*nodeSetIt);
|
||||||
|
if ( theSurface.IsNull() ) { // smooth in 3D
|
||||||
coord[0] += node->X();
|
coord[0] += node->X();
|
||||||
coord[1] += node->Y();
|
coord[1] += node->Y();
|
||||||
coord[2] += node->Z();
|
coord[2] += node->Z();
|
||||||
}
|
}
|
||||||
double nbNodes = nodeSet.size();
|
else { // smooth in 2D
|
||||||
theMesh->MoveNode (theNode,
|
gp_XY* uv = theUVMap[ node ];
|
||||||
coord[0]/nbNodes,
|
coord[0] += uv->X();
|
||||||
coord[1]/nbNodes,
|
coord[1] += uv->Y();
|
||||||
coord[2]/nbNodes);
|
}
|
||||||
|
}
|
||||||
|
int nbNodes = nodeSet.size();
|
||||||
|
coord[0] /= nbNodes;
|
||||||
|
coord[1] /= nbNodes;
|
||||||
|
|
||||||
|
if ( !theSurface.IsNull() ) {
|
||||||
|
theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
|
||||||
|
gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
|
||||||
|
coord[0] = p3d.X();
|
||||||
|
coord[1] = p3d.Y();
|
||||||
|
coord[2] = p3d.Z();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
coord[2] /= nbNodes;
|
||||||
|
|
||||||
|
// move node
|
||||||
|
|
||||||
|
const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
//=======================================================================
|
//=======================================================================
|
||||||
@ -1343,23 +1366,21 @@ void laplacianSmooth(SMESHDS_Mesh * theMesh,
|
|||||||
// surrounding elements
|
// surrounding elements
|
||||||
//=======================================================================
|
//=======================================================================
|
||||||
|
|
||||||
void centroidalSmooth(SMESHDS_Mesh * theMesh,
|
void centroidalSmooth(const SMDS_MeshNode* theNode,
|
||||||
const SMDS_MeshNode* theNode,
|
const Handle(Geom_Surface)& theSurface,
|
||||||
const set<const SMDS_MeshElement*> & theElems,
|
map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
|
||||||
const set<const SMDS_MeshNode*> & theFixedNodes)
|
|
||||||
{
|
{
|
||||||
gp_XYZ aNewXYZ(0.,0.,0.);
|
gp_XYZ aNewXYZ(0.,0.,0.);
|
||||||
SMESH::Controls::Area anAreaFunc;
|
SMESH::Controls::Area anAreaFunc;
|
||||||
double totalArea = 0.;
|
double totalArea = 0.;
|
||||||
int nbElems = 0;
|
int nbElems = 0;
|
||||||
|
|
||||||
|
// compute new XYZ
|
||||||
|
|
||||||
SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator();
|
SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator();
|
||||||
while ( elemIt->more() )
|
while ( elemIt->more() )
|
||||||
{
|
{
|
||||||
const SMDS_MeshElement* elem = elemIt->next();
|
const SMDS_MeshElement* elem = elemIt->next();
|
||||||
if ( theElems.find( elem ) == theElems.end() )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
nbElems++;
|
nbElems++;
|
||||||
|
|
||||||
gp_XYZ elemCenter(0.,0.,0.);
|
gp_XYZ elemCenter(0.,0.,0.);
|
||||||
@ -1370,6 +1391,10 @@ void centroidalSmooth(SMESHDS_Mesh * theMesh,
|
|||||||
const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
|
const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
|
||||||
gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
|
gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
|
||||||
aNodePoints.push_back( aP );
|
aNodePoints.push_back( aP );
|
||||||
|
if ( !theSurface.IsNull() ) { // smooth in 2D
|
||||||
|
gp_XY* uv = theUVMap[ aNode ];
|
||||||
|
aP.SetCoord( uv->X(), uv->Y(), 0. );
|
||||||
|
}
|
||||||
elemCenter += aP;
|
elemCenter += aP;
|
||||||
}
|
}
|
||||||
double elemArea = anAreaFunc.GetValue( aNodePoints );
|
double elemArea = anAreaFunc.GetValue( aNodePoints );
|
||||||
@ -1378,12 +1403,38 @@ void centroidalSmooth(SMESHDS_Mesh * theMesh,
|
|||||||
aNewXYZ += elemCenter * elemArea;
|
aNewXYZ += elemCenter * elemArea;
|
||||||
}
|
}
|
||||||
aNewXYZ /= totalArea;
|
aNewXYZ /= totalArea;
|
||||||
theMesh->MoveNode (theNode,
|
if ( !theSurface.IsNull() ) {
|
||||||
aNewXYZ.X(),
|
theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
|
||||||
aNewXYZ.Y(),
|
aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
|
||||||
aNewXYZ.Z());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// move node
|
||||||
|
|
||||||
|
const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
|
||||||
|
}
|
||||||
|
|
||||||
|
//=======================================================================
|
||||||
|
//function : getClosestUV
|
||||||
|
//purpose : return UV of closest projection
|
||||||
|
//=======================================================================
|
||||||
|
|
||||||
|
static bool getClosestUV (Extrema_GenExtPS& projector,
|
||||||
|
const gp_Pnt& point,
|
||||||
|
gp_XY & result)
|
||||||
|
{
|
||||||
|
projector.Perform( point );
|
||||||
|
if ( projector.IsDone() ) {
|
||||||
|
double u, v, minVal = DBL_MAX;
|
||||||
|
for ( int i = projector.NbExt(); i > 0; i-- )
|
||||||
|
if ( projector.Value( i ) < minVal ) {
|
||||||
|
minVal = projector.Value( i );
|
||||||
|
projector.Point( i ).Parameter( u, v );
|
||||||
|
}
|
||||||
|
result.SetCoord( u, v );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
//=======================================================================
|
//=======================================================================
|
||||||
//function : Smooth
|
//function : Smooth
|
||||||
//purpose : Smooth theElements during theNbIterations or until a worst
|
//purpose : Smooth theElements during theNbIterations or until a worst
|
||||||
@ -1402,87 +1453,334 @@ void SMESH_MeshEditor::Smooth (set<const SMDS_MeshElement*> & theElems,
|
|||||||
{
|
{
|
||||||
MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
|
MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
|
||||||
|
|
||||||
SMESHDS_Mesh* aMesh = GetMeshDS();
|
|
||||||
if ( theElems.empty() ) {
|
|
||||||
// add all faces
|
|
||||||
SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
|
|
||||||
while ( fIt->more() )
|
|
||||||
theElems.insert( fIt->next() );
|
|
||||||
}
|
|
||||||
|
|
||||||
set<const SMDS_MeshNode*> setMovableNodes;
|
|
||||||
|
|
||||||
// Fill setMovableNodes
|
|
||||||
|
|
||||||
map< const SMDS_MeshNode*, int > mapNodeNbFaces;
|
|
||||||
set< const SMDS_MeshElement* >::iterator itElem;
|
|
||||||
for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
|
|
||||||
{
|
|
||||||
const SMDS_MeshElement* elem = (*itElem);
|
|
||||||
if ( !elem || elem->GetType() != SMDSAbs_Face )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
SMDS_ElemIteratorPtr itN = elem->nodesIterator();
|
|
||||||
while ( itN->more() ) {
|
|
||||||
const SMDS_MeshNode* node =
|
|
||||||
static_cast<const SMDS_MeshNode*>( itN->next() );
|
|
||||||
|
|
||||||
if ( theFixedNodes.find( node ) != theFixedNodes.end() )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// if node is on edge => it is fixed
|
|
||||||
SMDS_PositionPtr aPositionPtr = node->GetPosition();
|
|
||||||
if ( aPositionPtr.get() &&
|
|
||||||
(aPositionPtr->GetTypeOfPosition() == SMDS_TOP_EDGE ||
|
|
||||||
aPositionPtr->GetTypeOfPosition() == SMDS_TOP_VERTEX)) {
|
|
||||||
theFixedNodes.insert( node );
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// fill mapNodeNbFaces in order to detect fixed boundary nodes
|
|
||||||
map<const SMDS_MeshNode*,int>::iterator nodeNbFacesIt =
|
|
||||||
mapNodeNbFaces.find ( node );
|
|
||||||
if ( nodeNbFacesIt == mapNodeNbFaces.end() )
|
|
||||||
mapNodeNbFaces.insert( map<const SMDS_MeshNode*,int>::value_type( node, 1 ));
|
|
||||||
else
|
|
||||||
(*nodeNbFacesIt).second++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// put not fixed nodes in setMovableNodes
|
|
||||||
map<const SMDS_MeshNode*,int>::iterator nodeNbFacesIt =
|
|
||||||
mapNodeNbFaces.begin();
|
|
||||||
for ( ; nodeNbFacesIt != mapNodeNbFaces.end(); nodeNbFacesIt++ ) {
|
|
||||||
const SMDS_MeshNode* node = (*nodeNbFacesIt).first;
|
|
||||||
// a node is on free boundary if it is shared by 1-2 faces
|
|
||||||
if ( (*nodeNbFacesIt).second > 2 )
|
|
||||||
setMovableNodes.insert( node );
|
|
||||||
else
|
|
||||||
theFixedNodes.insert( node );
|
|
||||||
}
|
|
||||||
|
|
||||||
// SMOOTHING //
|
|
||||||
|
|
||||||
if ( theTgtAspectRatio < 1.0 )
|
if ( theTgtAspectRatio < 1.0 )
|
||||||
theTgtAspectRatio = 1.0;
|
theTgtAspectRatio = 1.0;
|
||||||
|
|
||||||
SMESH::Controls::AspectRatio aQualityFunc;
|
SMESH::Controls::AspectRatio aQualityFunc;
|
||||||
|
|
||||||
for ( int it = 0; it < theNbIterations; it++ )
|
SMESHDS_Mesh* aMesh = GetMeshDS();
|
||||||
|
|
||||||
|
if ( theElems.empty() ) {
|
||||||
|
// add all faces to theElems
|
||||||
|
SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
|
||||||
|
while ( fIt->more() )
|
||||||
|
theElems.insert( fIt->next() );
|
||||||
|
}
|
||||||
|
// get all face ids theElems are on
|
||||||
|
set< int > faceIdSet;
|
||||||
|
set< const SMDS_MeshElement* >::iterator itElem;
|
||||||
|
for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
|
||||||
|
int fId = FindShape( *itElem );
|
||||||
|
// check that corresponding submesh exists and a shape is face
|
||||||
|
if (fId &&
|
||||||
|
faceIdSet.find( fId ) == faceIdSet.end() &&
|
||||||
|
aMesh->MeshElements( fId )) {
|
||||||
|
TopoDS_Shape F = aMesh->IndexToShape( fId );
|
||||||
|
if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
|
||||||
|
faceIdSet.insert( fId );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
|
||||||
|
|
||||||
|
// ===============================================
|
||||||
|
// smooth elements on each TopoDS_Face separately
|
||||||
|
// ===============================================
|
||||||
|
|
||||||
|
set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
|
||||||
|
for ( ; fId != faceIdSet.rend(); ++fId )
|
||||||
{
|
{
|
||||||
Standard_Real maxDisplacement = 0.;
|
// get face surface and submesh
|
||||||
set<const SMDS_MeshNode*>::iterator movableNodesIt
|
Handle(Geom_Surface) surface;
|
||||||
= setMovableNodes.begin();
|
SMESHDS_SubMesh* faceSubMesh = 0;
|
||||||
for ( ; movableNodesIt != setMovableNodes.end(); movableNodesIt++ )
|
TopoDS_Face face;
|
||||||
|
double fToler2 = 0, vPeriod = 0., uPeriod = 0.;
|
||||||
|
double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
|
||||||
|
bool isUPeriodic = false, isVPeriodic = false;
|
||||||
|
if ( *fId ) {
|
||||||
|
face = TopoDS::Face( aMesh->IndexToShape( *fId ));
|
||||||
|
surface = BRep_Tool::Surface( face );
|
||||||
|
faceSubMesh = aMesh->MeshElements( *fId );
|
||||||
|
fToler2 = BRep_Tool::Tolerance( face );
|
||||||
|
fToler2 *= fToler2;
|
||||||
|
isUPeriodic = surface->IsUPeriodic();
|
||||||
|
if ( isUPeriodic )
|
||||||
|
vPeriod = surface->UPeriod();
|
||||||
|
isVPeriodic = surface->IsVPeriodic();
|
||||||
|
if ( isVPeriodic )
|
||||||
|
uPeriod = surface->VPeriod();
|
||||||
|
surface->Bounds( u1, u2, v1, v2 );
|
||||||
|
}
|
||||||
|
// ---------------------------------------------------------
|
||||||
|
// for elements on a face, find movable and fixed nodes and
|
||||||
|
// compute UV for them
|
||||||
|
// ---------------------------------------------------------
|
||||||
|
bool checkBoundaryNodes = false;
|
||||||
|
set<const SMDS_MeshNode*> setMovableNodes, checkedNodes;
|
||||||
|
map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
|
||||||
|
list< gp_XY > listUV; // uvs the 2 maps refer to
|
||||||
|
list< const SMDS_MeshElement* > elemsOnFace;
|
||||||
|
|
||||||
|
Extrema_GenExtPS projector;
|
||||||
|
GeomAdaptor_Surface surfAdaptor;
|
||||||
|
if ( !surface.IsNull() ) {
|
||||||
|
surfAdaptor.Load( surface );
|
||||||
|
projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
|
||||||
|
}
|
||||||
|
int nbElemOnFace = 0;
|
||||||
|
itElem = theElems.begin();
|
||||||
|
while ( itElem != theElems.end() ) // loop on not yet smoothed elements
|
||||||
{
|
{
|
||||||
const SMDS_MeshNode* node = (*movableNodesIt);
|
const SMDS_MeshElement* elem = (*itElem);
|
||||||
|
if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
|
||||||
|
( faceSubMesh && !faceSubMesh->Contains( elem ))) {
|
||||||
|
++itElem;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
elemsOnFace.push_back( elem );
|
||||||
|
theElems.erase( itElem++ );
|
||||||
|
nbElemOnFace++;
|
||||||
|
|
||||||
|
// loop on elem nodes
|
||||||
|
SMDS_ElemIteratorPtr itN = elem->nodesIterator();
|
||||||
|
while ( itN->more() )
|
||||||
|
{
|
||||||
|
const SMDS_MeshNode* node =
|
||||||
|
static_cast<const SMDS_MeshNode*>( itN->next() );
|
||||||
|
if ( !checkedNodes.insert( node ).second )
|
||||||
|
continue;
|
||||||
|
// get UV on face
|
||||||
|
gp_XY uv( 0, 0 );
|
||||||
|
bool project = !surface.IsNull();
|
||||||
|
gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
|
||||||
|
const SMDS_PositionPtr& pos = node->GetPosition();
|
||||||
|
SMDS_TypeOfPosition posType = SMDS_TOP_3DSPACE;
|
||||||
|
if ( faceSubMesh && pos.get() ) {
|
||||||
|
posType = pos->GetTypeOfPosition();
|
||||||
|
if ( posType == SMDS_TOP_FACE ) {
|
||||||
|
SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos.get();
|
||||||
|
uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
|
||||||
|
gp_Pnt pSurf = surface->Value( uv.X(), uv.Y() );
|
||||||
|
project = pSurf.SquareDistance( pNode ) > fToler2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( project ) {
|
||||||
|
if ( !getClosestUV( projector, pNode, uv ))
|
||||||
|
MESSAGE("Node Projection Failed " << node);
|
||||||
|
if ( isUPeriodic )
|
||||||
|
uv.SetX( ElCLib::InPeriod( uv.X(), u1, u2 ));
|
||||||
|
if ( isVPeriodic )
|
||||||
|
uv.SetY( ElCLib::InPeriod( uv.Y(), v1, v2 ));
|
||||||
|
}
|
||||||
|
if ( !surface.IsNull() ) {
|
||||||
|
listUV.push_back( uv );
|
||||||
|
uvMap.insert( make_pair( node, &listUV.back() ));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( posType == SMDS_TOP_3DSPACE )
|
||||||
|
checkBoundaryNodes = true;
|
||||||
|
|
||||||
|
// movable or not?
|
||||||
|
if (posType != SMDS_TOP_EDGE &&
|
||||||
|
posType != SMDS_TOP_VERTEX &&
|
||||||
|
theFixedNodes.find( node ) == theFixedNodes.end())
|
||||||
|
{
|
||||||
|
// check if all faces around the node are on faceSubMesh
|
||||||
|
SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
|
||||||
|
bool all = true;
|
||||||
|
while ( eIt->more() && all ) {
|
||||||
|
const SMDS_MeshElement* e = eIt->next();
|
||||||
|
if ( e->GetType() == SMDSAbs_Face )
|
||||||
|
all = faceSubMesh->Contains( e );
|
||||||
|
}
|
||||||
|
if ( all )
|
||||||
|
setMovableNodes.insert( node );
|
||||||
|
else
|
||||||
|
checkBoundaryNodes = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // loop on elem nodes
|
||||||
|
|
||||||
|
if ( nbElemOnFace == faceSubMesh->NbElements() )
|
||||||
|
break; // all elements found
|
||||||
|
|
||||||
|
} // loop on not yet smoothed elements
|
||||||
|
|
||||||
|
if ( !faceSubMesh || elemsOnFace.size() != nbElemOnFace )
|
||||||
|
checkBoundaryNodes = true;
|
||||||
|
|
||||||
|
// fix nodes on boundary of elemsOnFace
|
||||||
|
|
||||||
|
if ( checkBoundaryNodes )
|
||||||
|
{
|
||||||
|
typedef pair<const SMDS_MeshNode*, const SMDS_MeshNode*> TLink;
|
||||||
|
map< TLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
|
||||||
|
map< TLink, int >::iterator link_nb;
|
||||||
|
// put all elements links to linkNbMap
|
||||||
|
list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
|
||||||
|
for ( ; elemIt != elemsOnFace.end(); ++elemIt )
|
||||||
|
{
|
||||||
|
// put elem nodes in array
|
||||||
|
vector< const SMDS_MeshNode* > nodes;
|
||||||
|
nodes.reserve( (*elemIt)->NbNodes() + 1 );
|
||||||
|
SMDS_ElemIteratorPtr itN = (*elemIt)->nodesIterator();
|
||||||
|
while ( itN->more() )
|
||||||
|
nodes.push_back( static_cast<const SMDS_MeshNode*>( itN->next() ));
|
||||||
|
nodes.push_back( nodes.front() );
|
||||||
|
// loop on elem links: insert them in linkNbMap
|
||||||
|
for ( int iN = 1; iN < nodes.size(); ++iN ) {
|
||||||
|
TLink link;
|
||||||
|
if ( nodes[ iN-1 ]->GetID() < nodes[ iN ]->GetID() )
|
||||||
|
link = make_pair( nodes[ iN-1 ], nodes[ iN ] );
|
||||||
|
else
|
||||||
|
link = make_pair( nodes[ iN ], nodes[ iN-1 ] );
|
||||||
|
link_nb = linkNbMap.find( link );
|
||||||
|
if ( link_nb == linkNbMap.end() )
|
||||||
|
linkNbMap.insert( make_pair ( link, 1 ));
|
||||||
|
else
|
||||||
|
link_nb->second++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// remove nodes that are in links encountered only once from setMovableNodes
|
||||||
|
for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
|
||||||
|
if ( link_nb->second == 1 ) {
|
||||||
|
setMovableNodes.erase( link_nb->first.first );
|
||||||
|
setMovableNodes.erase( link_nb->first.second );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------
|
||||||
|
// for nodes on seam edge, compute one more UV ( uvMap2 );
|
||||||
|
// find movable nodes linked to nodes on seam and which
|
||||||
|
// are to be smoothed using the second UV ( uvMap2 )
|
||||||
|
// -----------------------------------------------------
|
||||||
|
|
||||||
|
set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
|
||||||
|
if ( !surface.IsNull() )
|
||||||
|
{
|
||||||
|
TopExp_Explorer eExp( face, TopAbs_EDGE );
|
||||||
|
for ( ; eExp.More(); eExp.Next() )
|
||||||
|
{
|
||||||
|
TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
|
||||||
|
if ( !BRep_Tool::IsClosed( edge, face ))
|
||||||
|
continue;
|
||||||
|
SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
|
||||||
|
if ( !sm ) continue;
|
||||||
|
// find out which parameter varies for a node on seam
|
||||||
|
double f,l;
|
||||||
|
gp_Pnt2d uv1, uv2;
|
||||||
|
Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
|
||||||
|
if ( pcurve.IsNull() ) continue;
|
||||||
|
uv1 = pcurve->Value( f );
|
||||||
|
edge.Reverse();
|
||||||
|
pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
|
||||||
|
if ( pcurve.IsNull() ) continue;
|
||||||
|
uv2 = pcurve->Value( f );
|
||||||
|
int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
|
||||||
|
// assure uv1 < uv2
|
||||||
|
if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
|
||||||
|
gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
|
||||||
|
}
|
||||||
|
// get nodes on seam and its vertices
|
||||||
|
list< const SMDS_MeshNode* > seamNodes;
|
||||||
|
SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
|
||||||
|
while ( nSeamIt->more() )
|
||||||
|
seamNodes.push_back( nSeamIt->next() );
|
||||||
|
TopExp_Explorer vExp( edge, TopAbs_VERTEX );
|
||||||
|
for ( ; vExp.More(); vExp.Next() ) {
|
||||||
|
sm = aMesh->MeshElements( vExp.Current() );
|
||||||
|
if ( sm ) {
|
||||||
|
nSeamIt = sm->GetNodes();
|
||||||
|
while ( nSeamIt->more() )
|
||||||
|
seamNodes.push_back( nSeamIt->next() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// loop on nodes on seam
|
||||||
|
list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
|
||||||
|
for ( ; noSeIt != seamNodes.end(); ++noSeIt )
|
||||||
|
{
|
||||||
|
const SMDS_MeshNode* nSeam = *noSeIt;
|
||||||
|
map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
|
||||||
|
if ( n_uv == uvMap.end() )
|
||||||
|
continue;
|
||||||
|
// set the first UV
|
||||||
|
n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
|
||||||
|
// set the second UV
|
||||||
|
listUV.push_back( *n_uv->second );
|
||||||
|
listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
|
||||||
|
if ( uvMap2.empty() )
|
||||||
|
uvMap2 = uvMap; // copy the uvMap contents
|
||||||
|
uvMap2[ nSeam ] = &listUV.back();
|
||||||
|
|
||||||
|
// collect movable nodes linked to ones on seam in nodesNearSeam
|
||||||
|
SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator();
|
||||||
|
while ( eIt->more() )
|
||||||
|
{
|
||||||
|
const SMDS_MeshElement* e = eIt->next();
|
||||||
|
if ( e->GetType() != SMDSAbs_Face )
|
||||||
|
continue;
|
||||||
|
int nbUseMap1 = 0, nbUseMap2 = 0;
|
||||||
|
SMDS_ElemIteratorPtr nIt = e->nodesIterator();
|
||||||
|
while ( nIt->more() )
|
||||||
|
{
|
||||||
|
const SMDS_MeshNode* n =
|
||||||
|
static_cast<const SMDS_MeshNode*>( nIt->next() );
|
||||||
|
if (n == nSeam ||
|
||||||
|
setMovableNodes.find( n ) == setMovableNodes.end() )
|
||||||
|
continue;
|
||||||
|
// add only nodes being closer to uv2 than to uv1
|
||||||
|
gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
|
||||||
|
0.5 * ( n->Y() + nSeam->Y() ),
|
||||||
|
0.5 * ( n->Z() + nSeam->Z() ));
|
||||||
|
gp_XY uv;
|
||||||
|
getClosestUV( projector, pMid, uv );
|
||||||
|
if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
|
||||||
|
nodesNearSeam.insert( n );
|
||||||
|
nbUseMap2++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
nbUseMap1++;
|
||||||
|
}
|
||||||
|
// for centroidalSmooth all element nodes must
|
||||||
|
// be on one side of a seam
|
||||||
|
if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 )
|
||||||
|
{
|
||||||
|
SMDS_ElemIteratorPtr nIt = e->nodesIterator();
|
||||||
|
while ( nIt->more() ) {
|
||||||
|
const SMDS_MeshNode* n =
|
||||||
|
static_cast<const SMDS_MeshNode*>( nIt->next() );
|
||||||
|
setMovableNodes.erase( n );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // loop on nodes on seam
|
||||||
|
} // loop on edge of a face
|
||||||
|
} // if ( !face.IsNull() )
|
||||||
|
|
||||||
|
// -------------
|
||||||
|
// SMOOTHING //
|
||||||
|
// -------------
|
||||||
|
|
||||||
|
set<const SMDS_MeshNode*>::iterator nodeToMove;
|
||||||
|
int it = -1;
|
||||||
|
double maxRatio = -1., maxDisplacement = -1.;
|
||||||
|
for ( it = 0; it < theNbIterations; it++ )
|
||||||
|
{
|
||||||
|
maxDisplacement = 0.;
|
||||||
|
nodeToMove = setMovableNodes.begin();
|
||||||
|
for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ )
|
||||||
|
{
|
||||||
|
const SMDS_MeshNode* node = (*nodeToMove);
|
||||||
gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
|
gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
|
||||||
|
|
||||||
// smooth
|
// smooth
|
||||||
|
bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
|
||||||
if ( theSmoothMethod == LAPLACIAN )
|
if ( theSmoothMethod == LAPLACIAN )
|
||||||
laplacianSmooth( aMesh, node, theElems, theFixedNodes );
|
laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
|
||||||
else
|
else
|
||||||
centroidalSmooth( aMesh, node, theElems, theFixedNodes );
|
centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
|
||||||
|
|
||||||
// displacement
|
// node displacement
|
||||||
gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
|
gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
|
||||||
Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
|
Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
|
||||||
if ( aDispl > maxDisplacement )
|
if ( aDispl > maxDisplacement )
|
||||||
@ -1490,12 +1788,12 @@ void SMESH_MeshEditor::Smooth (set<const SMDS_MeshElement*> & theElems,
|
|||||||
}
|
}
|
||||||
// no node movement => exit
|
// no node movement => exit
|
||||||
if ( maxDisplacement < 1.e-16 ) {
|
if ( maxDisplacement < 1.e-16 ) {
|
||||||
MESSAGE("-- no node movement -- maxDisplacement: " << maxDisplacement << " it "<< it);
|
MESSAGE("-- no node movement --");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check elements quality
|
// check elements quality
|
||||||
double maxRatio = 0;
|
maxRatio = 0;
|
||||||
for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
|
for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
|
||||||
{
|
{
|
||||||
const SMDS_MeshElement* elem = (*itElem);
|
const SMDS_MeshElement* elem = (*itElem);
|
||||||
@ -1509,15 +1807,40 @@ void SMESH_MeshEditor::Smooth (set<const SMDS_MeshElement*> & theElems,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( maxRatio <= theTgtAspectRatio ) {
|
if ( maxRatio <= theTgtAspectRatio ) {
|
||||||
MESSAGE("-- quality achived -- maxRatio " << maxRatio << " it "<< it);
|
MESSAGE("-- quality achived --");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (it+1 == theNbIterations) {
|
if (it+1 == theNbIterations) {
|
||||||
MESSAGE("-- Iteration limit exceeded --");
|
MESSAGE("-- Iteration limit exceeded --");
|
||||||
}
|
}
|
||||||
|
} // smoothing iterations
|
||||||
|
|
||||||
|
MESSAGE(" Face id: " << *fId <<
|
||||||
|
" Nb iterstions: " << it <<
|
||||||
|
" Displacement: " << maxDisplacement <<
|
||||||
|
" Aspect Ratio " << maxRatio);
|
||||||
|
|
||||||
|
// ---------------------------------------
|
||||||
|
// new nodes positions are computed,
|
||||||
|
// record movement in DS and set new UV
|
||||||
|
// ---------------------------------------
|
||||||
|
|
||||||
|
nodeToMove = setMovableNodes.begin();
|
||||||
|
for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ )
|
||||||
|
{
|
||||||
|
SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
|
||||||
|
aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
|
||||||
|
map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
|
||||||
|
if ( node_uv != uvMap.end() ) {
|
||||||
|
gp_XY* uv = node_uv->second;
|
||||||
|
node->SetPosition
|
||||||
|
( SMDS_PositionPtr( new SMDS_FacePosition( *fId, uv->X(), uv->Y() )));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // loop on face ids
|
||||||
|
}
|
||||||
|
|
||||||
//=======================================================================
|
//=======================================================================
|
||||||
//function : isReverse
|
//function : isReverse
|
||||||
//purpose : Return true if normal of prevNodes is not co-directied with
|
//purpose : Return true if normal of prevNodes is not co-directied with
|
||||||
|
Loading…
Reference in New Issue
Block a user