1 // Copyright (C) 2007-2020 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
22 // File : SMESH_DeMerge.hxx
23 // Created : Fri Mar 10 16:06:54 2017
24 // Author : Edward AGAPOV (eap)
26 // Implementation of SMESH_MeshAlgos::DeMerge()
28 #include "SMESH_MeshAlgos.hxx"
30 #include "SMDS_VolumeTool.hxx"
31 #include "SMDS_MeshVolume.hxx"
35 bool isDegenFace(const std::vector< const SMDS_MeshNode* >& nodes)
37 // in a degenerated face each link sticks to another
39 typedef std::map< SMESH_TLink , int > TLink2Nb;
41 for ( size_t iPrev = nodes.size() - 1, i = 0; i < nodes.size(); iPrev = i++ )
43 SMESH_TLink link( nodes[iPrev], nodes[i] );
44 TLink2Nb::iterator l2n = link2nb.insert( std::make_pair( link, 0 )).first;
48 if ( link2nb.size() == 1 )
51 for ( TLink2Nb::iterator l2n = link2nb.begin(); l2n != link2nb.end(); ++l2n )
52 if ( l2n->second == 1 )
58 void deMergeFace(const SMDS_MeshElement* face,
59 std::vector< const SMDS_MeshNode* >& newNodes,
60 std::vector< const SMDS_MeshNode* >& noMergeNodes)
62 if ( face->IsQuadratic() )
64 const int nbCorners = face->NbCornerNodes();
65 const int nbNodes = (int) newNodes.size();
67 // de-merge sticking medium nodes
68 for ( int i = 1; i < nbNodes; i += 2 ) // loop om medium nodes
70 int iPrev = ( i - 1 );
71 int iNext = ( i + 1 ) % nbNodes;
72 if ( newNodes[ iPrev ] == newNodes[ iNext ] )
74 if ( newNodes[ iPrev ] != newNodes[ i ] || nbCorners == 3 )
76 // corners stick but the medium does not, or a link of triangle collapses
77 noMergeNodes.push_back( face->GetNode( iPrev / 2 ));
78 noMergeNodes.push_back( face->GetNode( iNext / 2 ));
79 noMergeNodes.push_back( face->GetNode( nbCorners + i / 2 ));
82 else if ( newNodes[ i ] == newNodes[ iPrev ] )
84 // the medium node sticks to a neighbor corner one
85 noMergeNodes.push_back( face->GetNode( nbCorners + i / 2 ));
86 noMergeNodes.push_back( face->GetNode( iPrev / 2 ));
88 else if ( newNodes[ i ] == newNodes[ iNext ] )
90 // the medium node sticks to a neighbor corner one
91 noMergeNodes.push_back( face->GetNode( nbCorners + i / 2 ));
92 noMergeNodes.push_back( face->GetNode( iNext / 2 ));
96 // find if the medium sticks to any other node
97 std::vector<const SMDS_MeshNode*>::iterator pos;
98 pos = std::find( newNodes.begin(), newNodes.begin() + iPrev, newNodes[i] );
99 if ( pos == newNodes.begin() + iPrev )
100 pos = std::find( newNodes.begin() + i + 1, newNodes.end(), newNodes[i] );
101 if ( pos == newNodes.end() )
104 int iStick = std::distance( newNodes.begin(), pos );
105 if ( iStick % 2 == 0 )
107 // the medium sticks to a distant corner
108 noMergeNodes.push_back( face->GetNode( nbCorners + i / 2 ));
109 noMergeNodes.push_back( face->GetNode( iStick / 2 ));
113 // the medium sticks to a distant medium;
114 // it's OK if two links stick
115 int iPrev2 = ( iStick - 1 );
116 int iNext2 = ( iStick + 1 ) % nbNodes;
117 if (( newNodes[ iPrev ] == newNodes[ iPrev2 ] &&
118 newNodes[ iNext ] == newNodes[ iNext2 ] )
120 ( newNodes[ iPrev ] == newNodes[ iNext2 ] &&
121 newNodes[ iNext ] == newNodes[ iPrev2 ] ))
125 noMergeNodes.push_back( face->GetNode( nbCorners + i / 2 ));
126 noMergeNodes.push_back( face->GetNode( nbCorners + iStick / 2 ));
134 bool isDegenVolume(const SMDS_VolumeTool& vt)
136 // TMP: it's necessary to use a topological check instead of a geometrical one
137 return vt.GetSize() < 1e-100;
140 void deMergeVolume(const SMDS_VolumeTool& vt,
141 std::vector< const SMDS_MeshNode* >& noMergeNodes)
143 // temporary de-merge all nodes
144 for ( int i = 0; i < vt.NbNodes(); ++i )
146 const SMDS_MeshNode* n = vt.GetNodes()[i];
147 if ( n != vt.Element()->GetNode( i ))
148 noMergeNodes.push_back( n );
154 //================================================================================
156 * \brief Find nodes whose merge makes the element invalid. (Degenerated elem is OK)
157 * \param [in] elem - the element
158 * \param [in] newNodes - nodes of the element after the merge
159 * \param [out] noMergeNodes - nodes to undo merge
161 //================================================================================
163 void SMESH_MeshAlgos::DeMerge(const SMDS_MeshElement* elem,
164 std::vector< const SMDS_MeshNode* >& newNodes,
165 std::vector< const SMDS_MeshNode* >& noMergeNodes)
167 switch ( elem->GetType() )
171 if ( newNodes.size() <= 4 )
172 return; // degenerated
174 if ( elem->IsQuadratic() )
175 SMDS_MeshCell::applyInterlace // interlace medium and corner nodes
176 ( SMDS_MeshCell::interlacedSmdsOrder( elem->GetEntityType(), newNodes.size() ), newNodes );
178 if ( isDegenFace( newNodes ))
181 deMergeFace( elem, newNodes, noMergeNodes );
187 if ( newNodes.size() <= 4 )
188 return; // degenerated
191 if ( !vt.Set( elem, /*skipCentral=*/true, &newNodes ))
194 if ( isDegenVolume( vt ))
197 deMergeVolume( elem, noMergeNodes );
203 if ( newNodes.size() == 3 )
204 if (( newNodes[2] == newNodes[0] && newNodes[2] != newNodes[1] ) ||
205 ( newNodes[2] == newNodes[1] && newNodes[2] != newNodes[0]))
207 // the medium node sticks to a corner
208 noMergeNodes.push_back( newNodes[2] );
209 noMergeNodes.push_back( newNodes[ newNodes[2] == newNodes[1] ]);