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