Salome HOME
Merging with WPdev
[modules/smesh.git] / src / StdMeshers / StdMeshers_Projection_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_Projection_3D.cxx
25 // Module    : SMESH
26 // Created   : Fri Oct 20 11:37:07 2006
27 // Author    : Edward AGAPOV (eap)
28
29
30 #include "StdMeshers_Projection_3D.hxx"
31 #include "StdMeshers_ProjectionSource3D.hxx"
32
33 #include "StdMeshers_ProjectionUtils.hxx"
34
35 #include "SMESHDS_Hypothesis.hxx"
36 #include "SMESHDS_SubMesh.hxx"
37 #include "SMESH_Block.hxx"
38 #include "SMESH_Gen.hxx"
39 #include "SMESH_Mesh.hxx"
40 #include "SMESH_MeshEditor.hxx"
41 #include "SMESH_Pattern.hxx"
42 #include "SMESH_subMesh.hxx"
43 #include "SMESH_subMeshEventListener.hxx"
44 #include "SMESH_MesherHelper.hxx"
45 #include "SMDS_VolumeTool.hxx"
46 #include "SMDS_PolyhedralVolumeOfNodes.hxx"
47
48 #include "utilities.h"
49
50 #define RETURN_BAD_RESULT(msg) { MESSAGE(msg); return false; }
51 #define gpXYZ(n) gp_XYZ(n->X(),n->Y(),n->Z())
52 #define SHOWYXZ(msg, xyz) // {\
53 // gp_Pnt p (xyz); \
54 // cout << msg << " ("<< p.X() << "; " <<p.Y() << "; " <<p.Z() << ") " <<endl;\
55 // }
56
57 typedef StdMeshers_ProjectionUtils TAssocTool;
58
59
60 //=======================================================================
61 //function : StdMeshers_Projection_3D
62 //purpose  : 
63 //=======================================================================
64
65 StdMeshers_Projection_3D::StdMeshers_Projection_3D(int hypId, int studyId, SMESH_Gen* gen)
66   :SMESH_3D_Algo(hypId, studyId, gen)
67 {
68   _name = "Projection_3D";
69   _shapeType = (1 << TopAbs_SHELL) | (1 << TopAbs_SOLID);       // 1 bit per shape type
70
71   _compatibleHypothesis.push_back("ProjectionSource3D");
72   _sourceHypo = 0;
73 }
74
75 //================================================================================
76 /*!
77  * \brief Destructor
78  */
79 //================================================================================
80
81 StdMeshers_Projection_3D::~StdMeshers_Projection_3D()
82 {}
83
84 //=======================================================================
85 //function : CheckHypothesis
86 //purpose  : 
87 //=======================================================================
88
89 bool StdMeshers_Projection_3D::CheckHypothesis(SMESH_Mesh&                          aMesh,
90                                                const TopoDS_Shape&                  aShape,
91                                                SMESH_Hypothesis::Hypothesis_Status& aStatus)
92 {
93   // check aShape that must be a 6 faces block
94   if ( TAssocTool::Count( aShape, TopAbs_SHELL, 1 ) != 1 ||
95        TAssocTool::Count( aShape, TopAbs_FACE , 1 ) != 6 ||
96        TAssocTool::Count( aShape, TopAbs_EDGE , 1 ) != 12 ||
97        TAssocTool::Count( aShape, TopAbs_WIRE , 1 ) != 6 )
98   {
99     aStatus = HYP_BAD_GEOMETRY;
100     return false;
101   }
102
103   list <const SMESHDS_Hypothesis * >::const_iterator itl;
104
105   const list <const SMESHDS_Hypothesis * >&hyps = GetUsedHypothesis(aMesh, aShape);
106   if ( hyps.size() == 0 )
107   {
108     aStatus = SMESH_Hypothesis::HYP_MISSING;
109     return false;  // can't work with no hypothesis
110   }
111
112   if ( hyps.size() > 1 )
113   {
114     aStatus = SMESH_Hypothesis::HYP_ALREADY_EXIST;
115     return false;
116   }
117
118   const SMESHDS_Hypothesis *theHyp = hyps.front();
119
120   string hypName = theHyp->GetName();
121
122   aStatus = SMESH_Hypothesis::HYP_OK;
123
124   if (hypName == "ProjectionSource3D")
125   {
126     _sourceHypo = static_cast<const StdMeshers_ProjectionSource3D *>(theHyp);
127     // Check hypo parameters
128
129     SMESH_Mesh* srcMesh = _sourceHypo->GetSourceMesh();
130     SMESH_Mesh* tgtMesh = & aMesh;
131     if ( !srcMesh )
132       srcMesh = tgtMesh;
133
134     // check vertices
135     if ( _sourceHypo->HasVertexAssociation() )
136     {
137       // source vertices
138       TopoDS_Shape edge = TAssocTool::GetEdgeByVertices
139         ( srcMesh, _sourceHypo->GetSourceVertex(1), _sourceHypo->GetSourceVertex(2) );
140       if ( edge.IsNull() ||
141            !TAssocTool::IsSubShape( edge, srcMesh ) ||
142            !TAssocTool::IsSubShape( edge, _sourceHypo->GetSource3DShape() ))
143       {
144         SCRUTE((edge.IsNull()));
145         SCRUTE((TAssocTool::IsSubShape( edge, srcMesh )));
146         SCRUTE((TAssocTool::IsSubShape( edge, _sourceHypo->GetSource3DShape() )));
147         aStatus = SMESH_Hypothesis::HYP_BAD_PARAMETER;
148       }
149       else
150       {
151         // target vertices
152         edge = TAssocTool::GetEdgeByVertices
153           ( tgtMesh, _sourceHypo->GetTargetVertex(1), _sourceHypo->GetTargetVertex(2) );
154         if ( edge.IsNull() ||
155              !TAssocTool::IsSubShape( edge, tgtMesh ) ||
156              !TAssocTool::IsSubShape( edge, aShape ))
157         {
158           SCRUTE((edge.IsNull()));
159           SCRUTE((TAssocTool::IsSubShape( edge, tgtMesh )));
160           SCRUTE((TAssocTool::IsSubShape( edge, aShape )));
161           aStatus = SMESH_Hypothesis::HYP_BAD_PARAMETER;
162         }
163       }
164     }
165     // check a source shape
166     if ( !TAssocTool::IsSubShape( _sourceHypo->GetSource3DShape(), srcMesh ) ||
167          ( srcMesh == tgtMesh && aShape == _sourceHypo->GetSource3DShape()))
168     {
169       SCRUTE((TAssocTool::IsSubShape( _sourceHypo->GetSource3DShape(), srcMesh)));
170       SCRUTE((srcMesh == tgtMesh));
171       SCRUTE((aShape == _sourceHypo->GetSource3DShape()));
172       aStatus = SMESH_Hypothesis::HYP_BAD_PARAMETER;
173     }
174   }
175   else
176   {
177     aStatus = SMESH_Hypothesis::HYP_INCOMPATIBLE;
178   }
179   return ( aStatus == HYP_OK );
180 }
181
182 //=======================================================================
183 //function : Compute
184 //purpose  : 
185 //=======================================================================
186
187 bool StdMeshers_Projection_3D::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape)
188 {
189   if ( !_sourceHypo )
190     return false;
191
192   SMESH_Mesh * srcMesh = _sourceHypo->GetSourceMesh();
193   SMESH_Mesh * tgtMesh = & aMesh;
194   if ( !srcMesh )
195     srcMesh = tgtMesh;
196
197   SMESHDS_Mesh * srcMeshDS = srcMesh->GetMeshDS();
198   SMESHDS_Mesh * tgtMeshDS = tgtMesh->GetMeshDS();
199
200   // get shell from shape3D
201   TopoDS_Shell srcShell, tgtShell;
202   TopExp_Explorer exp( _sourceHypo->GetSource3DShape(), TopAbs_SHELL );
203   int nbShell;
204   for ( nbShell = 0; exp.More(); exp.Next(), ++nbShell )
205     srcShell = TopoDS::Shell( exp.Current() );
206   if ( nbShell != 1 )
207     RETURN_BAD_RESULT("There must be 1 shell in the source shape");
208
209   exp.Init( aShape, TopAbs_SHELL );
210   for ( nbShell = 0; exp.More(); exp.Next(), ++nbShell )
211     tgtShell = TopoDS::Shell( exp.Current() );
212   if ( nbShell != 1 )
213     RETURN_BAD_RESULT("There must be 1 shell in the target shape");
214
215   // Assure that mesh on a source shape is computed
216
217   SMESH_subMesh* srcSubMesh = srcMesh->GetSubMesh( _sourceHypo->GetSource3DShape() );
218   //SMESH_subMesh* tgtSubMesh = tgtMesh->GetSubMesh( aShape );
219
220   if ( tgtMesh == srcMesh && !aShape.IsSame( _sourceHypo->GetSource3DShape() )) {
221     if ( !TAssocTool::MakeComputed( srcSubMesh ))
222       RETURN_BAD_RESULT("Impossible to compute the source mesh");
223   }
224   else {
225     if ( !srcSubMesh->IsMeshComputed() )
226       RETURN_BAD_RESULT("Source mesh is not computed");
227   }
228
229   // Find 2 pairs of corresponding vertices
230
231   TopoDS_Vertex tgtV000, tgtV100, srcV000, srcV100;
232   TAssocTool::TShapeShapeMap shape2ShapeMap;
233
234   if ( _sourceHypo->HasVertexAssociation() )
235   {
236     tgtV000 = _sourceHypo->GetTargetVertex(1);
237     tgtV100 = _sourceHypo->GetTargetVertex(2);
238     srcV000 = _sourceHypo->GetSourceVertex(1);
239     srcV100 = _sourceHypo->GetSourceVertex(2);
240   }
241   else
242   {
243     if ( !TAssocTool::FindSubShapeAssociation( tgtShell, tgtMesh, srcShell, srcMesh,
244                                                shape2ShapeMap) )
245       RETURN_BAD_RESULT("FindSubShapeAssociation() failed");
246
247     exp.Init( tgtShell, TopAbs_EDGE );
248     TopExp::Vertices( TopoDS::Edge( exp.Current() ), tgtV000, tgtV100 );
249
250     if ( !shape2ShapeMap.IsBound( tgtV000 ) || !shape2ShapeMap.IsBound( tgtV100 ))
251       RETURN_BAD_RESULT("Shape associating not done");
252     srcV000 = TopoDS::Vertex( shape2ShapeMap( tgtV000 ));
253     srcV100 = TopoDS::Vertex( shape2ShapeMap( tgtV100 ));
254     if ( !TAssocTool::IsSubShape( srcV000, srcShell ) ||
255          !TAssocTool::IsSubShape( srcV100, srcShell ))
256       RETURN_BAD_RESULT("Wrong target vertices");
257   }
258
259   // Load 2 SMESH_Block's with src and tgt shells
260
261   SMESH_Block srcBlock, tgtBlock;
262   TopTools_IndexedMapOfOrientedShape scrShapes, tgtShapes;
263   if ( !tgtBlock.LoadBlockShapes( tgtShell, tgtV000, tgtV100, tgtShapes ))
264     RETURN_BAD_RESULT("SMESH_Block::LoadBlockShapes(tgtShell) failed");
265
266   if ( !srcBlock.LoadBlockShapes( srcShell, srcV000, srcV100, scrShapes ))
267     RETURN_BAD_RESULT("SMESH_Block::LoadBlockShapes(srcShell) failed");
268
269   // Find matching nodes of src and tgt shells
270
271   TNodeNodeMap src2tgtNodeMap;
272   for ( int fId = SMESH_Block::ID_FirstF; fId < SMESH_Block::ID_Shell; ++fId )
273   {
274     // Corresponding subshapes
275     TopoDS_Face srcFace = TopoDS::Face( scrShapes( fId ));
276     TopoDS_Face tgtFace = TopoDS::Face( tgtShapes( fId ));
277     if ( _sourceHypo->HasVertexAssociation() ) { // associate face subshapes
278       shape2ShapeMap.Clear();
279       vector< int > edgeIdVec;
280       SMESH_Block::GetFaceEdgesIDs( fId, edgeIdVec );
281       for ( int i = 0; i < edgeIdVec.size(); ++i ) {
282         int eID = edgeIdVec[ i ];
283         shape2ShapeMap.Bind( tgtShapes( eID ), scrShapes( eID ));
284         if ( i < 2 ) {
285           vector< int > vertexIdVec;
286           SMESH_Block::GetEdgeVertexIDs( eID, vertexIdVec );
287           shape2ShapeMap.Bind( tgtShapes( vertexIdVec[0] ), scrShapes( vertexIdVec[0] ));
288           shape2ShapeMap.Bind( tgtShapes( vertexIdVec[1] ), scrShapes( vertexIdVec[1] ));
289         }
290       }
291     }
292     // Find matching nodes of tgt and src faces
293     TNodeNodeMap faceMatchingNodes;
294     if ( ! TAssocTool::FindMatchingNodesOnFaces( srcFace, srcMesh, tgtFace, tgtMesh, 
295                                                  shape2ShapeMap, faceMatchingNodes ))
296       RETURN_BAD_RESULT("Different mesh on corresponding src and tgt faces: "
297                         << srcMeshDS->ShapeToIndex( srcFace ) << " and "
298                         << tgtMeshDS->ShapeToIndex( tgtFace ));
299
300     // put found matching nodes of 2 faces to the global map
301     src2tgtNodeMap.insert( faceMatchingNodes.begin(), faceMatchingNodes.end() );
302   }
303
304   // ------------------
305   // Make mesh
306   // ------------------
307
308   SMDS_VolumeTool volTool;
309   SMESH_MesherHelper helper( *tgtMesh );
310   helper.IsQuadraticSubMesh( aShape );
311
312   SMESHDS_SubMesh* srcSMDS = srcSubMesh->GetSubMeshDS();
313   SMDS_ElemIteratorPtr volIt = srcSMDS->GetElements();
314   while ( volIt->more() ) // loop on source volumes
315   {
316     const SMDS_MeshElement* srcVol = volIt->next();
317     if ( !srcVol || srcVol->GetType() != SMDSAbs_Volume )
318         continue;
319     int nbNodes = srcVol->NbNodes();
320     SMDS_VolumeTool::VolumeType  volType = volTool.GetType( nbNodes );
321     if ( srcVol->IsQuadratic() )
322       nbNodes = volTool.NbCornerNodes( volType );
323
324     // Find or create a new tgt node for each node of a src volume
325
326     vector< const SMDS_MeshNode* > nodes( nbNodes );
327     for ( int i = 0; i < nbNodes; ++i )
328     {
329       const SMDS_MeshNode* srcNode = srcVol->GetNode( i );
330       const SMDS_MeshNode* tgtNode = 0;
331       TNodeNodeMap::iterator sN_tN = src2tgtNodeMap.find( srcNode );
332       if ( sN_tN != src2tgtNodeMap.end() ) // found
333       {
334         tgtNode = sN_tN->second;
335       }
336       else // Create a new tgt node
337       {
338         // compute normalized parameters of source node in srcBlock
339         gp_Pnt srcCoord = gpXYZ( srcNode );
340         gp_XYZ srcParam;
341         if ( !srcBlock.ComputeParameters( srcCoord, srcParam ))
342           RETURN_BAD_RESULT("srcBlock.ComputeParameters() failed");
343         // compute coordinates of target node by srcParam
344         gp_XYZ tgtXYZ;
345         if ( !tgtBlock.ShellPoint( srcParam, tgtXYZ ))
346           RETURN_BAD_RESULT("tgtBlock.ShellPoint() failed");
347         // add node
348         SMDS_MeshNode* newNode = tgtMeshDS->AddNode( tgtXYZ.X(), tgtXYZ.Y(), tgtXYZ.Z() );
349         tgtMeshDS->SetNodeInVolume( newNode, helper.GetSubShapeID() );
350         tgtNode = newNode;
351         src2tgtNodeMap.insert( make_pair( srcNode, tgtNode ));
352       }
353       nodes[ i ] = tgtNode;
354     }
355
356     // Create a new volume
357
358     SMDS_MeshVolume * tgtVol = 0;
359     switch ( volType ) {
360     case SMDS_VolumeTool::TETRA     :
361     case SMDS_VolumeTool::QUAD_TETRA:
362       tgtVol = helper.AddVolume( nodes[0],
363                                  nodes[1],
364                                  nodes[2],
365                                  nodes[3]); break;
366     case SMDS_VolumeTool::PYRAM     :
367     case SMDS_VolumeTool::QUAD_PYRAM:
368       tgtVol = helper.AddVolume( nodes[0],
369                                  nodes[1],
370                                  nodes[2],
371                                  nodes[3],
372                                  nodes[4]); break;
373     case SMDS_VolumeTool::PENTA     :
374     case SMDS_VolumeTool::QUAD_PENTA:
375       tgtVol = helper.AddVolume( nodes[0],
376                                  nodes[1],
377                                  nodes[2],
378                                  nodes[3],
379                                  nodes[4],
380                                  nodes[5]); break;
381     case SMDS_VolumeTool::HEXA      :
382     case SMDS_VolumeTool::QUAD_HEXA :
383       tgtVol = helper.AddVolume( nodes[0],
384                                  nodes[1],
385                                  nodes[2],
386                                  nodes[3],
387                                  nodes[4],
388                                  nodes[5],
389                                  nodes[6],
390                                  nodes[7]); break;
391     default: // polyhedron
392       const SMDS_PolyhedralVolumeOfNodes * poly =
393         dynamic_cast<const SMDS_PolyhedralVolumeOfNodes*>( srcVol );
394       if ( !poly )
395         RETURN_BAD_RESULT("Unexpected volume type");
396       vector<int> quantities( poly->NbFaces(), 0 );
397       for ( int i = 0; i < quantities.size(); ++i )
398         quantities[ i ] = poly->NbFaceNodes( i + 1 );
399       tgtVol = tgtMeshDS->AddPolyhedralVolume( nodes, quantities );
400     }
401     if ( tgtVol ) {
402       tgtMeshDS->SetMeshElementOnShape( tgtVol, helper.GetSubShapeID() );
403     }
404   } // loop on volumes of src shell
405
406   return true;
407 }
408
409 //=============================================================================
410 /*!
411  * \brief Sets a default event listener to submesh of the source shape
412   * \param subMesh - submesh where algo is set
413  *
414  * This method is called when a submesh gets HYP_OK algo_state.
415  * After being set, event listener is notified on each event of a submesh.
416  * Arranges that CLEAN event is translated from source submesh to
417  * the submesh
418  */
419 //=============================================================================
420
421 void StdMeshers_Projection_3D::SetEventListener(SMESH_subMesh* subMesh)
422 {
423   if ( _sourceHypo && ! _sourceHypo->GetSource3DShape().IsNull() )
424   {
425     SMESH_Mesh* srcMesh = _sourceHypo->GetSourceMesh();
426     if ( !srcMesh )
427       srcMesh = subMesh->GetFather();
428
429     SMESH_subMesh* srcShapeSM =
430       srcMesh->GetSubMesh( _sourceHypo->GetSource3DShape() );
431
432     if ( srcShapeSM != subMesh )
433       subMesh->SetEventListener( new SMESH_subMeshEventListener(true),
434                                  SMESH_subMeshEventListenerData::MakeData( subMesh ),
435                                  srcShapeSM );
436   }
437 }
438