Salome HOME
Fix Redesign of SMESH documentation
[modules/smesh.git] / src / SMESHUtils / SMESH_DeMerge.cxx
1 // Copyright (C) 2007-2016  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
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.
10 //
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.
15 //
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
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22 // File      : SMESH_DeMerge.hxx
23 // Created   : Fri Mar 10 16:06:54 2017
24 // Author    : Edward AGAPOV (eap)
25
26 // Implementation of SMESH_MeshAlgos::DeMerge()
27
28 #include "SMESH_MeshAlgos.hxx"
29
30 #include "SMDS_VolumeTool.hxx"
31 #include "SMDS_MeshVolume.hxx"
32
33 namespace
34 {
35   bool isDegenFace(const std::vector< const SMDS_MeshNode* >& nodes)
36   {
37     // in a degenerated face each link sticks to another
38
39     typedef std::map< SMESH_TLink , int > TLink2Nb;
40     TLink2Nb link2nb;
41     for ( size_t iPrev = nodes.size() - 1, i = 0; i < nodes.size(); iPrev = i++ )
42     {
43       SMESH_TLink link( nodes[iPrev], nodes[i] );
44       TLink2Nb::iterator l2n = link2nb.insert( std::make_pair( link, 0 )).first;
45       l2n->second++;
46     }
47
48     if ( link2nb.size() == 1 )
49       return true;
50
51     for ( TLink2Nb::iterator l2n = link2nb.begin(); l2n != link2nb.end(); ++l2n )
52       if ( l2n->second == 1 )
53         return false;
54
55     return true;
56   }
57
58   void deMergeFace(const SMDS_MeshElement*              face,
59                    std::vector< const SMDS_MeshNode* >& newNodes,
60                    std::vector< const SMDS_MeshNode* >& noMergeNodes)
61   {
62     if ( face->IsQuadratic() )
63     {
64       const int nbCorners = face->NbCornerNodes();
65       const int nbNodes = (int) newNodes.size();
66
67       // de-merge sticking medium nodes
68       for ( int i = 1; i < nbNodes; i += 2 ) // loop om medium nodes
69       {
70         int iPrev = ( i - 1 );
71         int iNext = ( i + 1 ) % nbNodes;
72         if ( newNodes[ iPrev ] == newNodes[ iNext ] )
73         {
74           if ( newNodes[ iPrev ] != newNodes[ i ] || nbCorners == 3 )
75           {
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 ));
80           }
81         }
82         else if ( newNodes[ i ] == newNodes[ iPrev ] )
83         {
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 ));
87         }
88         else if ( newNodes[ i ] == newNodes[ iNext ] )
89         {
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 ));
93         }
94         else
95         {
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() )
102             continue;
103
104           int iStick = std::distance( newNodes.begin(), pos );
105           if ( iStick % 2 == 0 )
106           {
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 ));
110           }
111           else
112           {
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 ] )
119                 ||
120                 ( newNodes[ iPrev ] == newNodes[ iNext2 ] &&
121                   newNodes[ iNext ] == newNodes[ iPrev2 ] ))
122               ; // OK
123             else
124             {
125               noMergeNodes.push_back( face->GetNode( nbCorners + i / 2 ));
126               noMergeNodes.push_back( face->GetNode( nbCorners + iStick / 2 ));
127             }
128           }
129         }
130       }
131     }
132   } // deMergeFace()
133
134   bool isDegenVolume(const SMDS_VolumeTool& vt)
135   {
136     // TMP: it's necessary to use a topological check instead of a geometrical one
137     return vt.GetSize() < 1e-100;
138   }
139
140   void deMergeVolume(const SMDS_VolumeTool&               vt,
141                      std::vector< const SMDS_MeshNode* >& noMergeNodes)
142   {
143     // temporary de-merge all nodes
144     for ( int i = 0; i < vt.NbNodes(); ++i )
145     {
146       const SMDS_MeshNode* n = vt.GetNodes()[i];
147       if ( n != vt.Element()->GetNode( i ))
148         noMergeNodes.push_back( n );
149     }
150   }
151
152 } // namespace
153
154 //================================================================================
155 /*!
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 
160  */
161 //================================================================================
162
163 void SMESH_MeshAlgos::DeMerge(const SMDS_MeshElement*              elem,
164                               std::vector< const SMDS_MeshNode* >& newNodes,
165                               std::vector< const SMDS_MeshNode* >& noMergeNodes)
166 {
167   switch ( elem->GetType() )
168   {
169   case SMDSAbs_Face:
170   {
171     if ( newNodes.size() <= 4 )
172       return; // degenerated
173
174     if ( elem->IsQuadratic() )
175       SMDS_MeshCell::applyInterlace // interlace medium and corner nodes
176         ( SMDS_MeshCell::interlacedSmdsOrder( elem->GetEntityType(), newNodes.size() ), newNodes );
177
178     if ( isDegenFace( newNodes ))
179       return;
180
181     deMergeFace( elem, newNodes, noMergeNodes );
182   }
183   break;
184
185   case SMDSAbs_Volume:
186   {
187     if ( newNodes.size() <= 4 )
188       return; // degenerated
189
190     SMDS_VolumeTool vt;
191     if ( !vt.Set( elem, /*skipCentral=*/true, &newNodes ))
192       return; // strange
193
194     if ( isDegenVolume( vt ))
195       return;
196
197     deMergeVolume( elem, noMergeNodes );
198   }
199   break;
200
201   case SMDSAbs_Edge:
202   {
203     if ( newNodes.size() == 3 )
204       if (( newNodes[2] == newNodes[0] && newNodes[2] != newNodes[1] ) ||
205           ( newNodes[2] == newNodes[1] && newNodes[2] != newNodes[0]))
206       {
207         // the medium node sticks to a corner
208         noMergeNodes.push_back( newNodes[2] );
209         noMergeNodes.push_back( newNodes[ newNodes[2] == newNodes[1] ]);
210       }
211   }
212   break;
213   default:;
214   }
215 }