Salome HOME
Merging with WPdev
[modules/smesh.git] / src / StdMeshers / StdMeshers_RadialPrism_3D.cxx
1 //  SMESH SMESH : implementaion of SMESH idl descriptions
2 //
3 //  Copyright (C) 2003  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. 
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 //
24 // File      : StdMeshers_RadialPrism_3D.cxx
25 // Module    : SMESH
26 // Created   : Fri Oct 20 11:37:07 2006
27 // Author    : Edward AGAPOV (eap)
28
29
30 #include "StdMeshers_RadialPrism_3D.hxx"
31
32 #include "StdMeshers_ProjectionUtils.hxx"
33 #include "StdMeshers_NumberOfLayers.hxx"
34 #include "StdMeshers_LayerDistribution.hxx"
35 #include "StdMeshers_Prism_3D.hxx"
36 #include "StdMeshers_Regular_1D.hxx"
37
38 #include "SMDS_MeshNode.hxx"
39 #include "SMESHDS_SubMesh.hxx"
40 #include "SMESH_Gen.hxx"
41 #include "SMESH_Mesh.hxx"
42 #include "SMESH_MeshEditor.hxx"
43 #include "SMESH_MesherHelper.hxx"
44 #include "SMESH_subMesh.hxx"
45
46 #include "utilities.h"
47
48 #include <TopoDS_Solid.hxx>
49 #include <TopoDS_Shell.hxx>
50 #include <BRepTools.hxx>
51 #include <TopTools_ListIteratorOfListOfShape.hxx>
52 #include <BRepBuilderAPI_MakeEdge.hxx>
53 #include <gp.hxx>
54 #include <gp_Pnt.hxx>
55
56
57 using namespace std;
58
59 #define RETURN_BAD_RESULT(msg) { MESSAGE(msg); return false; }
60 #define gpXYZ(n) gp_XYZ(n->X(),n->Y(),n->Z())
61
62 typedef StdMeshers_ProjectionUtils TAssocTool;
63
64 //=======================================================================
65 //function : StdMeshers_RadialPrism_3D
66 //purpose  : 
67 //=======================================================================
68
69 StdMeshers_RadialPrism_3D::StdMeshers_RadialPrism_3D(int hypId, int studyId, SMESH_Gen* gen)
70   :SMESH_3D_Algo(hypId, studyId, gen)
71 {
72   _name = "RadialPrism_3D";
73   _shapeType = (1 << TopAbs_SOLID);     // 1 bit per shape type
74
75   _compatibleHypothesis.push_back("LayerDistribution");
76   _compatibleHypothesis.push_back("NumberOfLayers");
77   myNbLayerHypo = 0;
78   myDistributionHypo = 0;
79 }
80
81 //================================================================================
82 /*!
83  * \brief Destructor
84  */
85 //================================================================================
86
87 StdMeshers_RadialPrism_3D::~StdMeshers_RadialPrism_3D()
88 {}
89
90 //=======================================================================
91 //function : CheckHypothesis
92 //purpose  : 
93 //=======================================================================
94
95 bool StdMeshers_RadialPrism_3D::CheckHypothesis(SMESH_Mesh&                          aMesh,
96                                                 const TopoDS_Shape&                  aShape,
97                                                 SMESH_Hypothesis::Hypothesis_Status& aStatus)
98 {
99   // check aShape that must have 2 shells
100   if ( TAssocTool::Count( aShape, TopAbs_SOLID, 0 ) != 1 ||
101        TAssocTool::Count( aShape, TopAbs_SHELL, 0 ) != 2 )
102   {
103     aStatus = HYP_BAD_GEOMETRY;
104     return false;
105   }
106
107   myNbLayerHypo = 0;
108   myDistributionHypo = 0;
109
110   list <const SMESHDS_Hypothesis * >::const_iterator itl;
111
112   const list <const SMESHDS_Hypothesis * >&hyps = GetUsedHypothesis(aMesh, aShape);
113   if ( hyps.size() == 0 )
114   {
115     aStatus = SMESH_Hypothesis::HYP_MISSING;
116     return false;  // can't work with no hypothesis
117   }
118
119   if ( hyps.size() > 1 )
120   {
121     aStatus = SMESH_Hypothesis::HYP_ALREADY_EXIST;
122     return false;
123   }
124
125   const SMESHDS_Hypothesis *theHyp = hyps.front();
126
127   string hypName = theHyp->GetName();
128
129   if (hypName == "NumberOfLayers")
130   {
131     myNbLayerHypo = static_cast<const StdMeshers_NumberOfLayers *>(theHyp);
132     aStatus = SMESH_Hypothesis::HYP_OK;
133     return true;
134   }
135   if (hypName == "LayerDistribution")
136   {
137     myDistributionHypo = static_cast<const StdMeshers_LayerDistribution *>(theHyp);
138     aStatus = SMESH_Hypothesis::HYP_OK;
139     return true;
140   }
141   aStatus = SMESH_Hypothesis::HYP_INCOMPATIBLE;
142   return true;
143 }
144
145 //=======================================================================
146 //function : Compute
147 //purpose  : 
148 //=======================================================================
149
150 bool StdMeshers_RadialPrism_3D::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape)
151 {
152   TopExp_Explorer exp;
153   SMESHDS_Mesh * meshDS = aMesh.GetMeshDS();
154
155   myHelper = new SMESH_MesherHelper( aMesh );
156   myHelper->IsQuadraticSubMesh( aShape );
157   // to delete helper at exit from Compute()
158   std::auto_ptr<SMESH_MesherHelper> helperDeleter( myHelper );
159
160   // get 2 shells 
161   TopoDS_Solid solid = TopoDS::Solid( aShape );
162   TopoDS_Shell outerShell = BRepTools::OuterShell( solid );
163   TopoDS_Shape innerShell;
164   int nbShells = 0;
165   for ( TopoDS_Iterator It (solid); It.More(); It.Next(), ++nbShells )
166     if ( !outerShell.IsSame( It.Value() ))
167       innerShell = It.Value();
168   if ( nbShells != 2 )
169     RETURN_BAD_RESULT("Must be 2 shells");
170
171   // ----------------------------------
172   // Associate subshapes of the shells
173   // ----------------------------------
174
175   TAssocTool::TShapeShapeMap shape2ShapeMap;
176   if ( !TAssocTool::FindSubShapeAssociation( outerShell, &aMesh,
177                                              innerShell, &aMesh,
178                                              shape2ShapeMap) )
179     RETURN_BAD_RESULT("FindSubShapeAssociation failed");
180
181   // ------------------
182   // Make mesh
183   // ------------------
184
185   TNode2ColumnMap node2columnMap;
186   myLayerPositions.clear();
187
188   for ( exp.Init( outerShell, TopAbs_FACE ); exp.More(); exp.Next() )
189   {
190     // Corresponding subshapes
191     TopoDS_Face outFace = TopoDS::Face( exp.Current() );
192     TopoDS_Face inFace;
193     if ( !shape2ShapeMap.IsBound( outFace )) {
194       RETURN_BAD_RESULT("Association not found for face " << meshDS->ShapeToIndex( outFace ));
195     } else {
196       inFace = TopoDS::Face( shape2ShapeMap( outFace ));
197     }
198
199     // Find matching nodes of in and out faces
200     TNodeNodeMap nodeIn2OutMap;
201     if ( ! TAssocTool::FindMatchingNodesOnFaces( inFace, &aMesh, outFace, &aMesh,
202                                                  shape2ShapeMap, nodeIn2OutMap ))
203       RETURN_BAD_RESULT("Different mesh on corresponding out and in faces: "
204                         << meshDS->ShapeToIndex( outFace ) << " and "
205                         << meshDS->ShapeToIndex( inFace ));
206     // Create volumes
207
208     SMDS_ElemIteratorPtr faceIt = meshDS->MeshElements( inFace )->GetElements();
209     while ( faceIt->more() ) // loop on faces on inFace
210     {
211       const SMDS_MeshElement* face = faceIt->next();
212       if ( !face || face->GetType() != SMDSAbs_Face )
213         continue;
214       int nbNodes = face->NbNodes();
215       if ( face->IsQuadratic() )
216         nbNodes /= 2;
217
218       // find node columns for each node
219       vector< const TNodeColumn* > columns( nbNodes );
220       for ( int i = 0; i < nbNodes; ++i )
221       {
222         const SMDS_MeshNode* n = face->GetNode( i );
223         TNode2ColumnMap::iterator n_col = node2columnMap.find( n );
224         if ( n_col != node2columnMap.end() )
225           columns[ i ] = & n_col->second;
226         else
227           columns[ i ] = makeNodeColumn( node2columnMap, n, nodeIn2OutMap[ n ] );
228       }
229
230       StdMeshers_Prism_3D::AddPrisms( columns, myHelper );
231     }
232   } // loop on faces of out shell
233
234   return true;
235 }
236
237 //================================================================================
238 /*!
239  * \brief Create a column of nodes from outNode to inNode
240   * \param n2ColMap - map of node columns to add a created column
241   * \param outNode - botton node of a column
242   * \param inNode - top node of a column
243   * \retval const TNodeColumn* - a new column pointer
244  */
245 //================================================================================
246
247 TNodeColumn* StdMeshers_RadialPrism_3D::makeNodeColumn( TNode2ColumnMap&     n2ColMap,
248                                                         const SMDS_MeshNode* outNode,
249                                                         const SMDS_MeshNode* inNode)
250 {
251   SMESHDS_Mesh * meshDS = myHelper->GetMeshDS();
252   int shapeID = myHelper->GetSubShapeID();
253
254   if ( myLayerPositions.empty() )
255     computeLayerPositions( gpXYZ( inNode ), gpXYZ( outNode ));
256
257   int nbSegments = myLayerPositions.size() + 1;
258
259   TNode2ColumnMap::iterator n_col =
260     n2ColMap.insert( make_pair( outNode, TNodeColumn() )).first;
261   TNodeColumn & column = n_col->second;
262   column.resize( nbSegments + 1 );
263   column.front() = outNode;
264   column.back() =  inNode;
265
266   gp_XYZ p1 = gpXYZ( outNode );
267   gp_XYZ p2 = gpXYZ( inNode );
268   for ( int z = 1; z < nbSegments; ++z )
269   {
270     double r = myLayerPositions[ z - 1 ];
271     gp_XYZ p = ( 1 - r ) * p1 + r * p2;
272     SMDS_MeshNode* n = meshDS->AddNode( p.X(), p.Y(), p.Z() );
273     meshDS->SetNodeInVolume( n, shapeID );
274     column[ z ] = n;
275   }
276
277   return & column;
278 }
279
280 //================================================================================
281 //================================================================================
282 /*!
283  * \brief Class computing layers distribution using data of
284  *        StdMeshers_LayerDistribution hypothesis
285  */
286 //================================================================================
287 //================================================================================
288
289 class TNodeDistributor: private StdMeshers_Regular_1D
290 {
291   list <const SMESHDS_Hypothesis *> myUsedHyps;
292 public:
293   // -----------------------------------------------------------------------------
294   static TNodeDistributor* GetDistributor(SMESH_Mesh& aMesh)
295   {
296     const int myID = -1000;
297     map < int, SMESH_1D_Algo * > & algoMap = aMesh.GetGen()->_map1D_Algo;
298     map < int, SMESH_1D_Algo * >::iterator id_algo = algoMap.find( myID );
299     if ( id_algo == algoMap.end() )
300       return new TNodeDistributor( myID, 0, aMesh.GetGen() );
301     return static_cast< TNodeDistributor* >( id_algo->second );
302   }
303   // -----------------------------------------------------------------------------
304   bool Compute( vector< double > &                  positions,
305                 gp_Pnt                              pIn,
306                 gp_Pnt                              pOut,
307                 SMESH_Mesh&                         aMesh,
308                 const StdMeshers_LayerDistribution* hyp)
309   {
310     double len = pIn.Distance( pOut );
311     if ( len <= DBL_MIN ) RETURN_BAD_RESULT("Bad points");
312
313     if ( !hyp || !hyp->GetLayerDistribution() )
314       RETURN_BAD_RESULT("Bad StdMeshers_LayerDistribution hypothesis");
315     myUsedHyps.clear();
316     myUsedHyps.push_back( hyp->GetLayerDistribution() );
317
318     TopoDS_Edge edge = BRepBuilderAPI_MakeEdge( pIn, pOut );
319
320     SMESH_Hypothesis::Hypothesis_Status aStatus;
321     if ( !StdMeshers_Regular_1D::CheckHypothesis( aMesh, edge, aStatus ))
322       RETURN_BAD_RESULT("StdMeshers_Regular_1D::CheckHypothesis() failed with status "<<aStatus);
323
324     list< double > params;
325     if ( !StdMeshers_Regular_1D::computeInternalParameters( edge, params, false ))
326       RETURN_BAD_RESULT("StdMeshers_Regular_1D::computeInternalParameters() failed");
327
328     positions.clear();
329     positions.reserve( params.size() );
330     for (list<double>::iterator itU = params.begin(); itU != params.end(); itU++)
331       positions.push_back( *itU / len );
332     return true;
333   }
334 protected:
335   // -----------------------------------------------------------------------------
336   TNodeDistributor( int hypId, int studyId, SMESH_Gen* gen)
337     : StdMeshers_Regular_1D( hypId, studyId, gen)
338   {
339   }
340   // -----------------------------------------------------------------------------
341   virtual const list <const SMESHDS_Hypothesis *> &
342     GetUsedHypothesis(SMESH_Mesh &, const TopoDS_Shape &, const bool)
343   {
344     return myUsedHyps;
345   }
346   // -----------------------------------------------------------------------------
347 };
348
349 //================================================================================
350 /*!
351  * \brief Compute positions of nodes between the internal and the external surfaces
352   * \retval bool - is a success
353  */
354 //================================================================================
355
356 bool StdMeshers_RadialPrism_3D::computeLayerPositions(gp_Pnt pIn, gp_Pnt pOut)
357 {
358   if ( myNbLayerHypo )
359   {
360     int nbSegments = myNbLayerHypo->GetNumberOfLayers();
361     myLayerPositions.resize( nbSegments - 1 );
362     for ( int z = 1; z < nbSegments; ++z )
363       myLayerPositions[ z - 1 ] = double( z )/ double( nbSegments );
364     return true;
365   }
366   if ( myDistributionHypo ) {
367     SMESH_Mesh * mesh = myHelper->GetMesh();
368     return TNodeDistributor::GetDistributor(*mesh)->Compute( myLayerPositions, pIn, pOut,
369                                                              *mesh, myDistributionHypo );
370   }
371   RETURN_BAD_RESULT("Bad hypothesis");  
372 }