smesh/src/SMESHUtils/SMESH_DeMerge.cxx
eap 9dd045b97c 23258: [CEA 1804] Do not merge the middle nodes of quadratic elements
Add AvoidMakingHoles argument in MergeNodes()

+ Save mesh name in STL file
+ Fix binary STL export after change of sizeof(Standard_Boolean)
+ Add Import menu to mesh component popup
2017-03-14 15:43:27 +03:00

216 lines
7.1 KiB
C++

// Copyright (C) 2007-2016 CEA/DEN, EDF R&D, OPEN CASCADE
//
// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
//
// 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, or (at your option) any later version.
//
// 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
//
// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
//
// File : SMESH_DeMerge.hxx
// Created : Fri Mar 10 16:06:54 2017
// Author : Edward AGAPOV (eap)
// Implementation of SMESH_MeshAlgos::DeMerge()
#include "SMESH_MeshAlgos.hxx"
#include "SMDS_VolumeTool.hxx"
#include "SMDS_MeshVolume.hxx"
namespace
{
bool isDegenFace(const std::vector< const SMDS_MeshNode* >& nodes)
{
// in a degenerated face each link sticks to another
typedef std::map< SMESH_TLink , int > TLink2Nb;
TLink2Nb link2nb;
for ( size_t iPrev = nodes.size() - 1, i = 0; i < nodes.size(); iPrev = i++ )
{
SMESH_TLink link( nodes[iPrev], nodes[i] );
TLink2Nb::iterator l2n = link2nb.insert( std::make_pair( link, 0 )).first;
l2n->second++;
}
if ( link2nb.size() == 1 )
return true;
for ( TLink2Nb::iterator l2n = link2nb.begin(); l2n != link2nb.end(); ++l2n )
if ( l2n->second == 1 )
return false;
return true;
}
void deMergeFace(const SMDS_MeshElement* face,
std::vector< const SMDS_MeshNode* >& newNodes,
std::vector< const SMDS_MeshNode* >& noMergeNodes)
{
if ( face->IsQuadratic() )
{
const int nbCorners = face->NbCornerNodes();
const int nbNodes = (int) newNodes.size();
// de-merge sticking medium nodes
for ( int i = 1; i < nbNodes; i += 2 ) // loop om medium nodes
{
int iPrev = ( i - 1 );
int iNext = ( i + 1 ) % nbNodes;
if ( newNodes[ iPrev ] == newNodes[ iNext ] )
{
if ( newNodes[ iPrev ] != newNodes[ i ] || nbCorners == 3 )
{
// corners stick but the medium does not, or a link of triangle collapses
noMergeNodes.push_back( face->GetNode( iPrev / 2 ));
noMergeNodes.push_back( face->GetNode( iNext / 2 ));
noMergeNodes.push_back( face->GetNode( nbCorners + i / 2 ));
}
}
else if ( newNodes[ i ] == newNodes[ iPrev ] )
{
// the medium node sticks to a neighbor corner one
noMergeNodes.push_back( face->GetNode( nbCorners + i / 2 ));
noMergeNodes.push_back( face->GetNode( iPrev / 2 ));
}
else if ( newNodes[ i ] == newNodes[ iNext ] )
{
// the medium node sticks to a neighbor corner one
noMergeNodes.push_back( face->GetNode( nbCorners + i / 2 ));
noMergeNodes.push_back( face->GetNode( iNext / 2 ));
}
else
{
// find if the medium sticks to any other node
std::vector<const SMDS_MeshNode*>::iterator pos;
pos = std::find( newNodes.begin(), newNodes.begin() + iPrev, newNodes[i] );
if ( pos == newNodes.begin() + iPrev )
pos = std::find( newNodes.begin() + i + 1, newNodes.end(), newNodes[i] );
if ( pos == newNodes.end() )
continue;
int iStick = std::distance( newNodes.begin(), pos );
if ( iStick % 2 == 0 )
{
// the medium sticks to a distant corner
noMergeNodes.push_back( face->GetNode( nbCorners + i / 2 ));
noMergeNodes.push_back( face->GetNode( iStick / 2 ));
}
else
{
// the medium sticks to a distant medium;
// it's OK if two links stick
int iPrev2 = ( iStick - 1 );
int iNext2 = ( iStick + 1 ) % nbNodes;
if (( newNodes[ iPrev ] == newNodes[ iPrev2 ] &&
newNodes[ iNext ] == newNodes[ iNext2 ] )
||
( newNodes[ iPrev ] == newNodes[ iNext2 ] &&
newNodes[ iNext ] == newNodes[ iPrev2 ] ))
; // OK
else
{
noMergeNodes.push_back( face->GetNode( nbCorners + i / 2 ));
noMergeNodes.push_back( face->GetNode( nbCorners + iStick / 2 ));
}
}
}
}
}
} // deMergeFace()
bool isDegenVolume(const SMDS_VolumeTool& vt)
{
// TMP: it's necessary to use a topological check instead of a geometrical one
return vt.GetSize() < 1e-100;
}
void deMergeVolume(const SMDS_VolumeTool& vt,
std::vector< const SMDS_MeshNode* >& noMergeNodes)
{
// temporary de-merge all nodes
for ( int i = 0; i < vt.NbNodes(); ++i )
{
const SMDS_MeshNode* n = vt.GetNodes()[i];
if ( n != vt.Element()->GetNode( i ))
noMergeNodes.push_back( n );
}
}
} // namespace
//================================================================================
/*!
* \brief Find nodes whose merge makes the element invalid. (Degenerated elem is OK)
* \param [in] elem - the element
* \param [in] newNodes - nodes of the element after the merge
* \param [out] noMergeNodes - nodes to undo merge
*/
//================================================================================
void SMESH_MeshAlgos::DeMerge(const SMDS_MeshElement* elem,
std::vector< const SMDS_MeshNode* >& newNodes,
std::vector< const SMDS_MeshNode* >& noMergeNodes)
{
switch ( elem->GetType() )
{
case SMDSAbs_Face:
{
if ( newNodes.size() <= 4 )
return; // degenerated
if ( elem->IsQuadratic() )
SMDS_MeshCell::applyInterlace // interlace medium and corner nodes
( SMDS_MeshCell::interlacedSmdsOrder( elem->GetEntityType(), newNodes.size() ), newNodes );
if ( isDegenFace( newNodes ))
return;
deMergeFace( elem, newNodes, noMergeNodes );
}
break;
case SMDSAbs_Volume:
{
if ( newNodes.size() <= 4 )
return; // degenerated
SMDS_VolumeTool vt;
if ( !vt.Set( elem, /*skipCentral=*/true, &newNodes ))
return; // strange
if ( isDegenVolume( vt ))
return;
deMergeVolume( elem, noMergeNodes );
}
break;
case SMDSAbs_Edge:
{
if ( newNodes.size() == 3 )
if (( newNodes[2] == newNodes[0] && newNodes[2] != newNodes[1] ) ||
( newNodes[2] == newNodes[1] && newNodes[2] != newNodes[0]))
{
// the medium node sticks to a corner
noMergeNodes.push_back( newNodes[2] );
noMergeNodes.push_back( newNodes[ newNodes[2] == newNodes[1] ]);
}
}
break;
default:;
}
}