1 // Copyright (C) 2007-2021 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
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.
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.
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
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 // File : StdMeshers_PolyhedronPerSolid_3D.cxx
25 // Created : Fri Oct 20 11:37:07 2006
26 // Author : Edward AGAPOV (eap)
28 #include "StdMeshers_PolyhedronPerSolid_3D.hxx"
30 #include "SMESHDS_Mesh.hxx"
31 #include "SMESH_ControlsDef.hxx"
32 #include "SMESH_Gen.hxx"
33 #include "SMESH_Mesh.hxx"
34 #include "SMESH_MeshAlgos.hxx"
35 #include "SMESH_MeshEditor.hxx"
36 #include "SMESH_MesherHelper.hxx"
37 #include "SMESH_ProxyMesh.hxx"
38 #include "SMESH_subMesh.hxx"
39 #include "StdMeshers_PolygonPerFace_2D.hxx"
40 #include "StdMeshers_Regular_1D.hxx"
41 #include "StdMeshers_ViscousLayers.hxx"
43 #include <TopExp_Explorer.hxx>
50 struct _EdgeMesher : public StdMeshers_Regular_1D
52 _EdgeMesher( int hypId, SMESH_Gen* gen )
53 : StdMeshers_Regular_1D( hypId, gen )
55 _hypType = NB_SEGMENTS;
56 _ivalue[ NB_SEGMENTS_IND ] = 1;
60 //=======================================================================
63 //=======================================================================
65 const SMDS_MeshElement* addHexa( std::vector< const SMDS_MeshElement* >& faces,
66 const std::vector< int > & quantities,
67 SMESH_MesherHelper & helper )
69 const SMDS_MeshElement* newHexa = 0;
71 // check nb of nodes in faces
72 for ( size_t i = 0; i < quantities.size(); ++i )
73 if ( quantities[ i ] != 4 )
76 // look for a top face
77 const SMDS_MeshElement* topFace = 0;
78 const SMDS_MeshElement* botFace = faces[0];
79 std::vector< const SMDS_MeshNode* > nodes( 16 ); // last 8 is a working buffer
80 nodes.assign( botFace->begin_nodes(), botFace->end_nodes() );
81 for ( size_t iF = 1; iF < faces.size() && !topFace; ++iF )
83 bool hasCommonNode = false;
84 for ( int iN = 0; iN < quantities[ 0 ] && !hasCommonNode; ++iN )
85 hasCommonNode = ( faces[ iF ]->GetNodeIndex( nodes[ iN ]) >= 0 );
88 topFace = faces[ iF ];
91 nodes.resize( 8 ); // set top nodes after hexa nodes - [8-11]
92 nodes.insert( nodes.end(), topFace->begin_nodes(), topFace->end_nodes() );
94 nodes.insert( nodes.end(), nodes.begin() + 8, nodes.begin() + 12 );
96 // find corresponding nodes of top and bottom by finding a side face including 2 node of each
97 SMESHDS_Mesh* mesh = helper.GetMeshDS();
98 const SMDS_MeshElement* sideFace = 0;
100 for ( i = 8; i < nodes.size()-1 && !sideFace; ++i )
102 sideFace = mesh->FindFace( nodes[0], nodes[1], nodes[ i ], nodes[ i + 1 ]);
107 --i; // restore after ++i in the loop
108 bool botOriRight = SMESH_MeshAlgos::IsRightOrder( sideFace, nodes[ 0 ], nodes[ 1 ] );
109 bool topOriRight = SMESH_MeshAlgos::IsRightOrder( sideFace, nodes[ i ], nodes[ i + 1 ] );
110 if ( botOriRight == topOriRight )
112 nodes[ 4 ] = nodes[ i + 1 ];
113 nodes[ 5 ] = nodes[ i + 0 ];
114 nodes[ 6 ] = nodes[ i + 3 ];
115 nodes[ 7 ] = nodes[ i + 2 ];
119 nodes[ 4 ] = nodes[ i + 0 ];
120 nodes[ 5 ] = nodes[ i + 1 ];
121 nodes[ 6 ] = nodes[ i + 2 ];
122 nodes[ 7 ] = nodes[ i + 3 ];
125 newHexa = helper.AddVolume( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ],
126 nodes[ 4 ], nodes[ 5 ], nodes[ 6 ], nodes[ 7 ]);
131 //=======================================================================
132 //function : addTetra
134 //=======================================================================
136 const SMDS_MeshElement* addTetra( std::vector< const SMDS_MeshElement* >& faces,
137 const std::vector< int > & quantities,
138 SMESH_MesherHelper & helper )
140 const SMDS_MeshElement* newTetra = 0;
142 // check nb of nodes in faces
143 for ( size_t i = 0; i < quantities.size(); ++i )
144 if ( quantities[ i ] != 3 )
147 const SMDS_MeshElement* botFace = faces[0];
149 std::vector< const SMDS_MeshNode* > nodes( 6 );
150 nodes.assign( botFace->begin_nodes(), botFace->end_nodes() );
153 const SMDS_MeshNode* topNode = 0;
154 for ( size_t i = 0; i < 3 && !topNode; ++i )
156 topNode = faces[ 1 ]->GetNode( i );
157 if ( botFace->GetNodeIndex( topNode ) >= 0 )
163 nodes.push_back( topNode );
165 newTetra = helper.AddVolume( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
170 //=======================================================================
171 //function : addPenta
173 //=======================================================================
175 const SMDS_MeshElement* addPenta( std::vector< const SMDS_MeshElement* >& faces,
176 const std::vector< int > & quantities,
177 SMESH_MesherHelper & helper )
179 const SMDS_MeshElement* newPenta = 0;
181 // check nb of nodes in faces and find triangle faces
182 int trias[2] = { -1, -1 };
183 for ( size_t i = 0; i < quantities.size(); ++i )
184 if ( quantities[ i ] != 4 )
186 if ( quantities[ i ] != 3 )
188 int iTria = ( trias[0] != -1 );
189 if ( trias[ iTria ] != -1 )
193 if ( trias[1] == -1 )
196 int iSide = trias[0] + 1;
197 if ( iSide == trias[1] )
200 // use first side (otherwise, out of bounds)
203 const SMDS_MeshElement* botFace = faces[ trias[0]];
204 const SMDS_MeshElement* topFace = faces[ trias[1]];
205 const SMDS_MeshElement* sideFace = faces[ iSide ];
206 const SMDS_MeshNode* nodes[ 6 ] = { 0,0,0,0,0,0 };
207 for ( int i = 0 ; i < 3; ++i )
209 const SMDS_MeshNode* botNode = botFace->GetNode( i );
210 if ( sideFace->GetNodeIndex( botNode ) < 0 )
213 nodes[ bool( nodes[0] )] = botNode;
215 const SMDS_MeshNode* topNode = topFace->GetNode( i );
216 if ( sideFace->GetNodeIndex( topNode ) < 0 )
219 nodes[ 3 + bool( nodes[3]) ] = topNode;
221 bool botOriRight = SMESH_MeshAlgos::IsRightOrder( sideFace, nodes[ 0 ], nodes[ 1 ]);
222 bool topOriRight = SMESH_MeshAlgos::IsRightOrder( sideFace, nodes[ 3 ], nodes[ 4 ]);
223 if ( botOriRight == topOriRight )
224 std::swap( nodes[ 3 ], nodes[ 4 ]);
226 newPenta = helper.AddVolume( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ],
227 nodes[ 3 ], nodes[ 4 ], nodes[ 5 ]);
232 //=======================================================================
235 //=======================================================================
237 const SMDS_MeshElement* addPyra( std::vector< const SMDS_MeshElement* >& faces,
238 const std::vector< int > & quantities,
239 SMESH_MesherHelper & helper )
241 const SMDS_MeshElement* newPyra = 0;
243 // check nb of nodes in faces
245 for ( size_t i = 0; i < quantities.size(); ++i )
246 if ( quantities[ i ] != 3 )
248 if ( quantities[ i ] != 4 || iBot != -1 )
253 const SMDS_MeshElement* botFace = faces[ iBot ];
255 std::vector< const SMDS_MeshNode* > nodes( 8 );
256 nodes.assign( botFace->begin_nodes(), botFace->end_nodes() );
259 const SMDS_MeshNode* topNode = 0;
260 for ( size_t i = 0; i < 4 && !topNode; ++i )
262 topNode = faces[ 1 ]->GetNode( i );
263 if ( botFace->GetNodeIndex( topNode ) >= 0 )
269 nodes.push_back( topNode );
271 newPyra = helper.AddVolume( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ], nodes[4] );
276 //=======================================================================
277 //function : addHPrism
278 //purpose : add hexagonal prism
279 //=======================================================================
281 const SMDS_MeshElement* addHPrism( std::vector< const SMDS_MeshElement* >& faces,
282 const std::vector< int > & quantities,
283 SMESH_MesherHelper & helper )
285 const SMDS_MeshElement* newHexPrism = 0;
287 // check nb of nodes in faces and find hexagons
288 int hexa[2] = { -1, -1 };
289 for ( size_t i = 0; i < quantities.size(); ++i )
290 if ( quantities[ i ] != 4 )
292 if ( quantities[ i ] != 6 )
294 int iHex = ( hexa[0] != -1 );
295 if ( hexa[ iHex ] != -1 )
302 const SMDS_MeshElement* botFace = faces[ hexa[ 0 ]];
303 const SMDS_MeshElement* topFace = faces[ hexa[ 1 ]];
304 std::vector< const SMDS_MeshNode* > nodes( 24 ); // last 12 is a working buffer
306 nodes.assign( botFace->begin_nodes(), botFace->end_nodes() );
307 nodes.resize( 12 ); // set top nodes after hexa nodes - [12-17]
308 nodes.insert( nodes.end(), topFace->begin_nodes(), topFace->end_nodes() );
310 nodes.insert( nodes.end(), nodes.begin() + 12, nodes.begin() + 18 );
312 // find corresponding nodes of top and bottom by finding a side face including 2 node of each
313 SMESHDS_Mesh* mesh = helper.GetMeshDS();
314 const SMDS_MeshElement* sideFace = 0;
316 for ( i = 12; i < nodes.size()-1 && !sideFace; ++i )
318 sideFace = mesh->FindFace( nodes[0], nodes[1], nodes[ i ], nodes[ i + 1 ]);
323 --i; // restore after ++i in the loop
324 bool botOriRight = SMESH_MeshAlgos::IsRightOrder( sideFace, nodes[ 0 ], nodes[ 1 ] );
325 bool topOriRight = SMESH_MeshAlgos::IsRightOrder( sideFace, nodes[ i ], nodes[ i + 1 ] );
326 if ( botOriRight == topOriRight )
328 nodes[ 6 ] = nodes[ i + 1 ];
329 nodes[ 7 ] = nodes[ i + 0 ];
330 nodes[ 8 ] = nodes[ i + 5 ];
331 nodes[ 9 ] = nodes[ i + 4 ];
332 nodes[ 10 ] = nodes[ i + 3 ];
333 nodes[ 11 ] = nodes[ i + 2 ];
337 nodes[ 6 ] = nodes[ i + 0 ];
338 nodes[ 7 ] = nodes[ i + 1 ];
339 nodes[ 8 ] = nodes[ i + 2 ];
340 nodes[ 9 ] = nodes[ i + 3 ];
341 nodes[ 10 ] = nodes[ i + 4 ];
342 nodes[ 11 ] = nodes[ i + 5 ];
345 newHexPrism = helper.AddVolume( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ],
346 nodes[ 3 ], nodes[ 4 ], nodes[ 5 ],
347 nodes[ 6 ], nodes[ 7 ], nodes[ 8 ],
348 nodes[ 9 ], nodes[10 ], nodes[11 ]);
353 //=======================================================================
356 //=======================================================================
358 const SMDS_MeshElement* addPoly( std::vector< const SMDS_MeshElement* >& faces,
359 const std::vector< int > & quantities,
360 SMESH_MesherHelper & helper )
362 const SMDS_MeshElement* newPoly = 0;
364 std::vector< const SMDS_MeshNode* > nodes;
365 for ( size_t iF = 0; iF < faces.size(); ++iF )
366 nodes.insert( nodes.end(), faces[iF]->begin_nodes(), faces[iF]->end_nodes() );
368 newPoly = helper.AddPolyhedralVolume( nodes, quantities );
375 //=======================================================================
376 //function : StdMeshers_PolyhedronPerSolid_3D
378 //=======================================================================
380 StdMeshers_PolyhedronPerSolid_3D::StdMeshers_PolyhedronPerSolid_3D(int hypId,
382 :SMESH_3D_Algo(hypId, gen),
383 myEdgeMesher( new _EdgeMesher( gen->GetANewId(), gen )),
384 myFaceMesher( new StdMeshers_PolygonPerFace_2D( gen->GetANewId(), gen ))
386 _name = "PolyhedronPerSolid_3D";
387 _requireDiscreteBoundary = false;
388 _supportSubmeshes = true;
389 _compatibleHypothesis.push_back("ViscousLayers");
390 _neededLowerHyps[0] = _neededLowerHyps[1] = _neededLowerHyps[2] = true;
393 //=======================================================================
394 //function : ~StdMeshers_PolyhedronPerSolid_3D
396 //=======================================================================
398 StdMeshers_PolyhedronPerSolid_3D::~StdMeshers_PolyhedronPerSolid_3D()
404 //=======================================================================
405 //function : CheckHypothesis
407 //=======================================================================
409 bool StdMeshers_PolyhedronPerSolid_3D::CheckHypothesis(SMESH_Mesh& theMesh,
410 const TopoDS_Shape& theShape,
411 Hypothesis_Status& theStatus)
413 myViscousLayersHyp = NULL;
415 const std::list<const SMESHDS_Hypothesis*>& hyps =
416 GetUsedHypothesis( theMesh, theShape, /*ignoreAuxiliary=*/false);
417 std::list <const SMESHDS_Hypothesis* >::const_iterator h = hyps.begin();
418 if ( h == hyps.end())
420 theStatus = SMESH_Hypothesis::HYP_OK;
424 // only StdMeshers_ViscousLayers can be used
426 for ( ; h != hyps.end(); ++h )
428 if ( !(myViscousLayersHyp = dynamic_cast< const StdMeshers_ViscousLayers*> ( *h )))
431 if ( !myViscousLayersHyp )
432 theStatus = HYP_INCOMPATIBLE;
434 error( myViscousLayersHyp->CheckHypothesis( theMesh, theShape, theStatus ));
436 return theStatus == HYP_OK;
439 //=======================================================================
442 //=======================================================================
444 bool StdMeshers_PolyhedronPerSolid_3D::Compute(SMESH_Mesh& theMesh,
445 const TopoDS_Shape& theShape)
447 const SMDS_MeshElement* newVolume = 0;
449 SMESH_subMesh* sm = theMesh.GetSubMesh( theShape );
450 SMESH_subMeshIteratorPtr smIt = sm->getDependsOnIterator( /*includeSelf=*/true,
451 /*complexFirst=*/false);
452 while ( smIt->more() )
455 if ( !sm->IsEmpty() )
458 const TopoDS_Shape & shape = sm->GetSubShape();
459 switch ( shape.ShapeType() )
462 sm->ComputeStateEngine( SMESH_subMesh::COMPUTE );
466 sm->ComputeStateEngine( SMESH_subMesh::COMPUTE );
468 myEdgeMesher->Compute( theMesh, shape );
472 sm->ComputeStateEngine( SMESH_subMesh::COMPUTE );
473 if ( sm->IsEmpty() && !myFaceMesher->Compute( theMesh, shape ))
475 sm->GetComputeError() = myFaceMesher->GetComputeError();
476 sm->GetComputeError()->myAlgo = myFaceMesher;
483 SMESH_MesherHelper helper( theMesh );
484 helper.SetElementsOnShape( true );
485 _quadraticMesh = helper.IsQuadraticSubMesh( shape );
487 SMESH_ProxyMesh::Ptr proxymesh( new SMESH_ProxyMesh( theMesh ));
488 if ( myViscousLayersHyp )
490 proxymesh = myViscousLayersHyp->Compute( theMesh, theShape );
495 std::vector< const SMDS_MeshElement* > faces;
498 for ( TopExp_Explorer faceEx( shape, TopAbs_FACE ); faceEx.More(); faceEx.Next() )
500 const SMESHDS_SubMesh* smDS = proxymesh->GetSubMesh( faceEx.Current() );
501 for ( SMDS_ElemIteratorPtr faceIt = smDS->GetElements(); faceIt->more(); )
502 faces.push_back( faceIt->next() );
505 bool useMediumNodes = false;
506 if ( !_quadraticMesh && theMesh.GetMeshDS()->GetMeshInfo().NbFaces( ORDER_QUADRATIC ))
507 for ( size_t i = 0; i < faces.size() && !useMediumNodes ; ++i )
508 useMediumNodes = faces[ i ]->IsQuadratic();
510 std::vector< int > quantities( faces.size() );
511 std::set< const SMDS_MeshNode* > nodes;
512 for ( size_t i = 0; i < faces.size(); ++i )
514 quantities[ i ] = useMediumNodes ? faces[ i ]->NbNodes() : faces[ i ]->NbCornerNodes();
515 for ( int iN = 0; iN < quantities[ i ]; ++iN )
516 nodes.insert( faces[ i ]->GetNode( iN ));
519 const size_t nbNodes = nodes.size(), nbFaces = faces.size();
520 if ( nbNodes == 8 && nbFaces == 6 ) newVolume = addHexa ( faces, quantities, helper );
521 else if ( nbNodes == 4 && nbFaces == 4 ) newVolume = addTetra ( faces, quantities, helper );
522 else if ( nbNodes == 6 && nbFaces == 5 ) newVolume = addPenta ( faces, quantities, helper );
523 else if ( nbNodes == 5 && nbFaces == 5 ) newVolume = addPyra ( faces, quantities, helper );
524 else if ( nbNodes == 12 && nbFaces == 8 ) newVolume = addHPrism( faces, quantities, helper );
526 newVolume = addPoly ( faces, quantities, helper );
530 SMESH::Controls::BadOrientedVolume checker;
531 checker.SetMesh( theMesh.GetMeshDS() );
532 if ( checker.IsSatisfy( newVolume->GetID() ))
534 SMESH_MeshEditor editor( &theMesh );
535 editor.Reorient( newVolume );
541 } // switch ( shape.ShapeType() )
542 } // loop on sub-meshes
547 //=======================================================================
548 //function : Evaluate
550 //=======================================================================
552 bool StdMeshers_PolyhedronPerSolid_3D::Evaluate(SMESH_Mesh& theMesh,
553 const TopoDS_Shape& theShape,
554 MapShapeNbElems& theResMap)
556 _quadraticMesh = false;
558 SMESH_subMesh* sm = theMesh.GetSubMesh( theShape );
559 SMESH_subMeshIteratorPtr smIt = sm->getDependsOnIterator( /*includeSelf=*/true,
560 /*complexFirst=*/false);
561 while ( smIt->more() )
565 MapShapeNbElems::iterator sm2vec = theResMap.find( sm );
566 if ( sm2vec != theResMap.end() && !sm2vec->second.empty() )
569 const TopoDS_Shape & shape = sm->GetSubShape();
570 switch ( shape.ShapeType() )
573 myEdgeMesher->Evaluate( theMesh, shape, theResMap );
578 myFaceMesher->Evaluate( theMesh, shape, theResMap );
579 std::vector<smIdType> & quantities = theResMap[ sm ];
580 _quadraticMesh = ( !quantities.empty() &&
581 ( quantities[ SMDSEntity_Quad_Triangle ] +
582 quantities[ SMDSEntity_Quad_Quadrangle ] +
583 quantities[ SMDSEntity_Quad_Polygon ]));
589 std::vector<smIdType> & quantities = theResMap[ sm ];
590 quantities.resize( SMDSEntity_Last, 0 );
592 SMESH_MesherHelper helper( theMesh );
593 const int nbNodes = helper.Count( shape, TopAbs_VERTEX, /*ignoreSame=*/true );
594 const int nbFaces = helper.Count( shape, TopAbs_FACE, /*ignoreSame=*/false );
596 if ( nbNodes == 8 && nbFaces == 6 )
597 quantities[ _quadraticMesh ? SMDSEntity_Quad_Hexa : SMDSEntity_Hexa ] = 1;
598 else if ( nbNodes == 4 && nbFaces == 4 )
599 quantities[ _quadraticMesh ? SMDSEntity_Quad_Tetra : SMDSEntity_Tetra ] = 1;
600 else if ( nbNodes == 6 && nbFaces == 5 )
601 quantities[ _quadraticMesh ? SMDSEntity_Quad_Penta : SMDSEntity_Penta ] = 1;
602 else if ( nbNodes == 5 && nbFaces == 5 )
603 quantities[ _quadraticMesh ? SMDSEntity_Quad_Pyramid : SMDSEntity_Pyramid ] = 1;
604 else if ( nbNodes == 12 && nbFaces == 8 )
605 quantities[ /*_quadraticMesh ? SMDSEntity_Quad_Pyramid :*/ SMDSEntity_Hexagonal_Prism ] = 1;
607 quantities[ /*_quadraticMesh ? SMDSEntity_Quad_Polyhedra : */SMDSEntity_Polyhedra ] = 1;
613 } // switch ( shape.ShapeType() )
614 } // loop on sub-meshes