Salome HOME
Merge branch 'V9_9_BR'
[modules/smesh.git] / src / StdMeshers / StdMeshers_BlockRenumber.cxx
1 // Copyright (C) 2007-2022  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
23 //  File   : StdMeshers_BlockRenumber.cxx
24 //  Author : Edward AGAPOV, OCC
25 //  Module : SMESH
26
27 #include "StdMeshers_BlockRenumber.hxx"
28
29 #include <SMDS_EdgePosition.hxx>
30 #include <SMDS_FacePosition.hxx>
31 #include <SMESHDS_Mesh.hxx>
32 #include <SMESHDS_SubMesh.hxx>
33 #include <SMESH_Algo.hxx>
34 #include <SMESH_Mesh.hxx>
35 #include <SMESH_MesherHelper.hxx>
36 #include <SMESH_TryCatch.hxx>
37 #include <SMESH_BoostTxtArchive.hxx>
38
39 #include <BRep_Tool.hxx>
40 #include <TopExp_Explorer.hxx>
41 #include <TopTools_MapOfShape.hxx>
42 #include <TopoDS.hxx>
43
44 #include <boost/archive/text_oarchive.hpp>
45
46 //=============================================================================
47 /*!
48  * Constructor 
49  */
50 //=============================================================================
51
52 StdMeshers_BlockRenumber::StdMeshers_BlockRenumber(int hypId, SMESH_Gen * gen)
53   :SMESH_Hypothesis(hypId, gen)
54 {
55   _name = "BlockRenumber";
56   _param_algo_dim = 3; // is used by StdMeshers_Hexa_3D and StdMeshers_CompositeHexa_3D
57 }
58
59 //================================================================================
60 /*!
61  * \brief Set local CS of blocks
62  */
63 //================================================================================
64
65 void StdMeshers_BlockRenumber::SetBlocksOrientation( std::vector< StdMeshers_BlockCS > & blockCS )
66 {
67   if ( _blockCS != blockCS )
68   {
69     NotifySubMeshesHypothesisModification();
70     _blockCS.swap( blockCS );
71     _solids2vertices.Clear();
72   }
73 }
74
75 //================================================================================
76 /*
77  * Return true and vertices if block orientation is defined for a given solid
78  */
79 //================================================================================
80
81 bool StdMeshers_BlockRenumber::IsSolidIncluded( SMESH_Mesh&         mesh,
82                                                 const TopoDS_Shape& solid,
83                                                 TopoDS_Vertex&      vertex000,
84                                                 TopoDS_Vertex&      vertex001 ) const
85 {
86   bool result = false;
87   vertex000.Nullify();
88   vertex001.Nullify();
89
90   if ( _solids2vertices.IsEmpty() )
91   {
92     StdMeshers_BlockRenumber* me = const_cast<StdMeshers_BlockRenumber*>(this);
93     for ( StdMeshers_BlockCS& bcs : me->_blockCS )
94     {
95       TopoDS_Shape so   = mesh.GetShapeByEntry( bcs._solid );
96       TopoDS_Shape s000 = mesh.GetShapeByEntry( bcs._vertex000 );
97       TopoDS_Shape s001 = mesh.GetShapeByEntry( bcs._vertex001 );
98       TopoDS_Vertex v000 = StdMeshers_RenumberHelper::GetVertexAtPoint( so, s000 );
99       TopoDS_Vertex v001 = StdMeshers_RenumberHelper::GetVertexAtPoint( so, s001 );
100       if ( !v000.IsNull() && !v001.IsNull() )
101       {
102         me->_solids2vertices.Bind( so, std::make_pair( v000, v001 ));
103         if ( so.IsSame( solid ))
104         {
105           result = true;
106           vertex000 = v000;
107           vertex001 = v001;
108         }
109       }
110     }
111   }
112   else if ( !solid.IsNull() )
113   {
114     if (( result = _solids2vertices.IsBound( solid )))
115     {
116       auto vvPairPtr = _solids2vertices.Seek( solid );
117       vertex000 = vvPairPtr->first;
118       vertex001 = vvPairPtr->second;
119     }
120   }
121   return result;
122 }
123
124 //=======================================================================
125 //function : CheckHypothesis
126 //purpose  : 
127 //=======================================================================
128
129 SMESH_ComputeErrorPtr StdMeshers_BlockRenumber::CheckHypothesis(SMESH_Mesh&         aMesh,
130                                                                 const TopoDS_Shape& /*shape*/) const
131 {
132   SMESH_Comment errorTxt;
133   for ( size_t i = 0; i < _blockCS.size() &&  errorTxt.empty(); ++i )
134   {
135     TopoDS_Shape solid = aMesh.GetShapeByEntry( _blockCS[i]._solid );
136     TopoDS_Shape  v000 = aMesh.GetShapeByEntry( _blockCS[i]._vertex000 );
137     TopoDS_Shape  v001 = aMesh.GetShapeByEntry( _blockCS[i]._vertex001 );
138     v000 = StdMeshers_RenumberHelper::GetVertexAtPoint( solid, v000 );
139     v001 = StdMeshers_RenumberHelper::GetVertexAtPoint( solid, v001 );
140
141     if ( solid.IsNull() || solid.ShapeType() != TopAbs_SOLID )
142       errorTxt << "Can't find a SOLID by entry '" << _blockCS[i]._solid << "'";
143     else if ( v000.IsNull() || v000.ShapeType() != TopAbs_VERTEX )
144       errorTxt << "Can't find a VERTEX by entry '" << _blockCS[i]._vertex000 << "'";
145     else if ( v001.IsNull() || v001.ShapeType() != TopAbs_VERTEX )
146       errorTxt << "Can't find a VERTEX by entry '" << _blockCS[i]._vertex001 << "'";
147     else if ( !SMESH_MesherHelper::IsSubShape( v000, solid ))
148       errorTxt << "VERTEX '" << _blockCS[i]._vertex001 << "' does not belong to SOLID '"
149                << _blockCS[i]._solid << "'";
150     else if ( !SMESH_MesherHelper::IsSubShape( v001, solid ))
151       errorTxt << "VERTEX '" << _blockCS[i]._vertex001 << "' does not belong to SOLID '"
152                << _blockCS[i]._solid << "'";
153     else if ( SMESH_MesherHelper::Count( solid, TopAbs_VERTEX, true ) == 8 &&
154               SMESH_MesherHelper::GetCommonAncestor( v000, v001, aMesh, TopAbs_EDGE ).IsNull() )
155       errorTxt << "Vertices '" << _blockCS[i]._vertex000 << "' and '" << _blockCS[i]._vertex001
156                << "' are not connected by an edge";
157   }
158
159   SMESH_ComputeErrorPtr error;
160   if ( !errorTxt.empty() )
161   {
162     error = SMESH_ComputeError::New( COMPERR_BAD_PARMETERS,
163                                      SMESH_Comment("Renumber hypothesis: ") << errorTxt );
164   }
165   return error;
166 }
167
168 //=======================================================================
169 //function : StdMeshers_RenumberHelper
170 //purpose  : constructor
171 //=======================================================================
172
173 StdMeshers_RenumberHelper::StdMeshers_RenumberHelper( SMESH_Mesh&                     mesh,
174                                                       const StdMeshers_BlockRenumber* hyp)
175   : _mesh( &mesh ), _hyp( hyp ), _newOldNodes( 2, nullptr )
176 {
177 }
178
179 //=======================================================================
180 //function : GetVertex000
181 //purpose  : Find default vertex at (0,0,0) local position
182 //=======================================================================
183
184 TopoDS_Vertex StdMeshers_RenumberHelper::GetVertex000( const TopTools_MapOfShape& cornerVertices )
185 {
186   TopoDS_Vertex v000;
187   if ( cornerVertices.Extent() < 8 )
188     return TopoDS_Vertex();
189
190   double minVal = DBL_MAX, minX = DBL_MAX, val;
191   for ( auto it = cornerVertices.cbegin(); it != cornerVertices.cend(); ++it )
192   {
193     gp_Pnt P = BRep_Tool::Pnt( TopoDS::Vertex( *it ));
194     val = P.X() + P.Y() + P.Z();
195     if ( val < minVal || ( val == minVal && P.X() < minX ))
196     {
197       v000 = TopoDS::Vertex( *it );
198       minVal = val;
199       minX = P.X();
200     }
201   }
202   return v000;
203 }
204
205 //=======================================================================
206 //function : GetVertexAtPoint
207 //purpose  : Return the VERTEX of solid at given point
208 //=======================================================================
209
210 TopoDS_Vertex StdMeshers_RenumberHelper::GetVertexAtPoint( const TopoDS_Shape& solid,
211                                                            const TopoDS_Shape& point )
212 {
213   if ( !solid.IsNull() && !point.IsNull() && point.ShapeType() == TopAbs_VERTEX )
214   {
215     gp_Pnt   p = BRep_Tool::Pnt( TopoDS::Vertex( point ));
216     double tol = Precision::Confusion();
217     for ( TopExp_Explorer exp( solid, TopAbs_VERTEX ); exp.More(); exp.Next() )
218     {
219       const TopoDS_Vertex& v = TopoDS::Vertex( exp.Current() );
220       if ( v.IsSame( point ) || p.IsEqual( BRep_Tool::Pnt( v ), tol ))
221         return v;
222     }
223   }
224   return TopoDS_Vertex();
225 }
226
227 //================================================================================
228 /*
229  * Create a copy of an old node and remember this couple of nodes for replacement
230  */
231 //================================================================================
232
233 void StdMeshers_RenumberHelper::AddReplacingNode( const SMDS_MeshNode* & oldNode )
234 {
235   SMESHDS_Mesh*     mesh = _mesh->GetMeshDS();
236   SMESH_NodeXYZ   oldXYZ = oldNode;
237   SMDS_MeshNode* newNode = mesh->AddNode( oldXYZ.X(), oldXYZ.Y(), oldXYZ.Z() );
238   _newOldNodes.front() = newNode;
239   _newOldNodes.back()  = oldNode;
240   _nodesToMerge.push_back( _newOldNodes );
241   oldNode = newNode;
242
243   int               shapeID = oldXYZ->GetShapeID();
244   const TopoDS_Shape& shape = mesh->IndexToShape( shapeID );
245   if ( !shape.IsNull() )
246     switch ( shape.ShapeType() )
247     {
248     case TopAbs_FACE:
249       if ( SMDS_FacePositionPtr pos = oldXYZ->GetPosition() )
250         mesh->SetNodeOnFace( newNode, shapeID, pos->GetUParameter(), pos->GetVParameter() );
251       break;
252     case TopAbs_EDGE:
253       if ( SMDS_EdgePositionPtr pos = oldXYZ->GetPosition() )
254         mesh->SetNodeOnEdge( newNode, shapeID, pos->GetUParameter() );
255       break;
256     case TopAbs_VERTEX:
257       mesh->SetNodeOnVertex( newNode, shapeID );
258       break;
259     default:
260       mesh->SetNodeInVolume( newNode, shapeID );
261     }
262 }
263
264 //================================================================================
265 /*
266  * Replace old nodes by new ones
267  */
268 //================================================================================
269
270 void StdMeshers_RenumberHelper::DoReplaceNodes()
271 {
272   SMESH_MeshEditor( _mesh ).MergeNodes( _nodesToMerge );
273 }
274
275 //=============================================================================
276 /*!
277  * Persistence
278  */
279 //=============================================================================
280
281 ostream & StdMeshers_BlockRenumber::SaveTo(ostream & save)
282 {
283   boost::archive::text_oarchive archive( save );
284   archive << *this;
285
286   return save;
287 }
288
289 //=============================================================================
290 /*!
291  * Persistence
292  */
293 //=============================================================================
294
295 istream & StdMeshers_BlockRenumber::LoadFrom(istream & load)
296 {
297   SMESH_TRY;
298
299   SMESHUtils::BoostTxtArchive( load ) >> *this;
300
301   SMESH_CATCH( SMESH::doNothing );
302
303   return load;
304 }
305
306 namespace boost {
307   namespace serialization {
308
309     //=======================================================================
310     //function : serialize
311     //purpose  : serialize StdMeshers_BlockCS
312     //=======================================================================
313
314     template<class Archive>
315     void serialize(Archive & ar, StdMeshers_BlockCS & blockCS, const unsigned int /*version*/)
316     {
317       ar & blockCS._solid;
318       ar & blockCS._vertex000;
319       ar & blockCS._vertex001;
320     }
321
322   } // namespace serialization
323 } // namespace boost