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