// Copyright (C) 2007-2020 CEA/DEN, EDF R&D, OPEN CASCADE // // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // // File : StdMeshers_BlockRenumber.cxx // Author : Edward AGAPOV, OCC // Module : SMESH #include "StdMeshers_BlockRenumber.hxx" #include "SMDS_EdgePosition.hxx" #include "SMDS_FacePosition.hxx" #include "SMESHDS_Mesh.hxx" #include "SMESHDS_SubMesh.hxx" #include "SMESH_Algo.hxx" #include "SMESH_Mesh.hxx" #include "SMESH_MesherHelper.hxx" #include "SMESH_TryCatch.hxx" #include #include #include #include #include #include //============================================================================= /*! * Constructor */ //============================================================================= StdMeshers_BlockRenumber::StdMeshers_BlockRenumber(int hypId, SMESH_Gen * gen) :SMESH_Hypothesis(hypId, gen) { _name = "BlockRenumber"; _param_algo_dim = 3; // is used by StdMeshers_Hexa_3D and StdMeshers_CompositeHexa_3D } //================================================================================ /*! * \brief Set local CS of blocks */ //================================================================================ void StdMeshers_BlockRenumber::SetBlocksOrientation( std::vector< StdMeshers_BlockCS > & blockCS ) { if ( _blockCS != blockCS ) { NotifySubMeshesHypothesisModification(); _blockCS.swap( blockCS ); _solids2vertices.Clear(); } } //================================================================================ /* * Return true and vertices if block orientation is defined for a given solid */ //================================================================================ bool StdMeshers_BlockRenumber::IsSolidIncluded( SMESH_Mesh& mesh, const TopoDS_Shape& solid, TopoDS_Vertex& vertex000, TopoDS_Vertex& vertex001 ) const { bool result = false; vertex000.Nullify(); vertex001.Nullify(); if ( _solids2vertices.IsEmpty() ) { StdMeshers_BlockRenumber* me = const_cast(this); for ( StdMeshers_BlockCS& bcs : me->_blockCS ) { TopoDS_Shape so = mesh.GetShapeByEntry( bcs._solid ); TopoDS_Shape s000 = mesh.GetShapeByEntry( bcs._vertex000 ); TopoDS_Shape s001 = mesh.GetShapeByEntry( bcs._vertex001 ); TopoDS_Vertex v000 = StdMeshers_RenumberHelper::GetVertexAtPoint( so, s000 ); TopoDS_Vertex v001 = StdMeshers_RenumberHelper::GetVertexAtPoint( so, s001 ); if ( !v000.IsNull() && !v001.IsNull() ) { me->_solids2vertices.Bind( so, std::make_pair( v000, v001 )); if ( so.IsSame( solid )) { result = true; vertex000 = v000; vertex001 = v001; } } } } else if ( !solid.IsNull() ) { if (( result = _solids2vertices.IsBound( solid ))) { auto vvPairPtr = _solids2vertices.Seek( solid ); vertex000 = vvPairPtr->first; vertex001 = vvPairPtr->second; } } return result; } //======================================================================= //function : CheckHypothesis //purpose : //======================================================================= SMESH_ComputeErrorPtr StdMeshers_BlockRenumber::CheckHypothesis(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape) const { SMESH_Comment errorTxt; for ( size_t i = 0; i < _blockCS.size() && errorTxt.empty(); ++i ) { TopoDS_Shape solid = aMesh.GetShapeByEntry( _blockCS[i]._solid ); TopoDS_Shape v000 = aMesh.GetShapeByEntry( _blockCS[i]._vertex000 ); TopoDS_Shape v001 = aMesh.GetShapeByEntry( _blockCS[i]._vertex001 ); v000 = StdMeshers_RenumberHelper::GetVertexAtPoint( solid, v000 ); v001 = StdMeshers_RenumberHelper::GetVertexAtPoint( solid, v001 ); if ( solid.IsNull() || solid.ShapeType() != TopAbs_SOLID ) errorTxt << "Can't find a SOLID by entry '" << _blockCS[i]._solid << "'"; else if ( v000.IsNull() || v000.ShapeType() != TopAbs_VERTEX ) errorTxt << "Can't find a VERTEX by entry '" << _blockCS[i]._vertex000 << "'"; else if ( v001.IsNull() || v001.ShapeType() != TopAbs_VERTEX ) errorTxt << "Can't find a VERTEX by entry '" << _blockCS[i]._vertex001 << "'"; else if ( !SMESH_MesherHelper::IsSubShape( v000, solid )) errorTxt << "VERTEX '" << _blockCS[i]._vertex001 << "' does not belong to SOLID '" << _blockCS[i]._solid << "'"; else if ( !SMESH_MesherHelper::IsSubShape( v001, solid )) errorTxt << "VERTEX '" << _blockCS[i]._vertex001 << "' does not belong to SOLID '" << _blockCS[i]._solid << "'"; else if ( SMESH_MesherHelper::Count( solid, TopAbs_VERTEX, true ) == 8 && SMESH_MesherHelper::GetCommonAncestor( v000, v001, aMesh, TopAbs_EDGE ).IsNull() ) errorTxt << "Vertices '" << _blockCS[i]._vertex000 << "' and '" << _blockCS[i]._vertex001 << "' are not connected by an edge"; } SMESH_ComputeErrorPtr error; if ( !errorTxt.empty() ) { error = SMESH_ComputeError::New( COMPERR_BAD_PARMETERS, SMESH_Comment("Renumber hypothesis: ") << errorTxt ); } return error; } //======================================================================= //function : StdMeshers_RenumberHelper //purpose : constructor //======================================================================= StdMeshers_RenumberHelper::StdMeshers_RenumberHelper( SMESH_Mesh& mesh, const StdMeshers_BlockRenumber* hyp) : _mesh( &mesh ), _hyp( hyp ), _newOldNodes( 2, nullptr ) { } //======================================================================= //function : GetVertex000 //purpose : Find default vertex at (0,0,0) local position //======================================================================= TopoDS_Vertex StdMeshers_RenumberHelper::GetVertex000( const TopTools_MapOfShape& cornerVertices ) { TopoDS_Vertex v000; if ( cornerVertices.Extent() < 8 ) return TopoDS_Vertex(); double minVal = DBL_MAX, minX = DBL_MAX, val; for ( auto it = cornerVertices.cbegin(); it != cornerVertices.cend(); ++it ) { gp_Pnt P = BRep_Tool::Pnt( TopoDS::Vertex( *it )); val = P.X() + P.Y() + P.Z(); if ( val < minVal || ( val == minVal && P.X() < minX )) { v000 = TopoDS::Vertex( *it ); minVal = val; minX = P.X(); } } return v000; } //======================================================================= //function : GetVertex000 //purpose : Find default vertex at (0,0,0) local position //======================================================================= TopoDS_Vertex StdMeshers_RenumberHelper::GetVertexAtPoint( const TopoDS_Shape& solid, const TopoDS_Shape& point ) { if ( !solid.IsNull() && !point.IsNull() && point.ShapeType() == TopAbs_VERTEX ) { gp_Pnt p = BRep_Tool::Pnt( TopoDS::Vertex( point )); double tol = Precision::Confusion(); for ( TopExp_Explorer exp( solid, TopAbs_VERTEX ); exp.More(); exp.Next() ) { const TopoDS_Vertex& v = TopoDS::Vertex( exp.Current() ); if ( v.IsSame( point ) || p.IsEqual( BRep_Tool::Pnt( v ), tol )) return v; } } return TopoDS_Vertex(); } //================================================================================ /* * Create a copy of an old node and remember this couple of nodes for replacement */ //================================================================================ void StdMeshers_RenumberHelper::AddReplacingNode( const SMDS_MeshNode* & oldNode ) { SMESHDS_Mesh* mesh = _mesh->GetMeshDS(); SMESH_NodeXYZ oldXYZ = oldNode; SMDS_MeshNode* newNode = mesh->AddNode( oldXYZ.X(), oldXYZ.Y(), oldXYZ.Z() ); _newOldNodes.front() = newNode; _newOldNodes.back() = oldNode; _nodesToMerge.push_back( _newOldNodes ); oldNode = newNode; int shapeID = oldXYZ->GetShapeID(); const TopoDS_Shape& shape = mesh->IndexToShape( shapeID ); if ( !shape.IsNull() ) switch ( shape.ShapeType() ) { case TopAbs_FACE: if ( SMDS_FacePositionPtr pos = oldXYZ->GetPosition() ) mesh->SetNodeOnFace( newNode, shapeID, pos->GetUParameter(), pos->GetVParameter() ); break; case TopAbs_EDGE: if ( SMDS_EdgePositionPtr pos = oldXYZ->GetPosition() ) mesh->SetNodeOnEdge( newNode, shapeID, pos->GetUParameter() ); break; case TopAbs_VERTEX: mesh->SetNodeOnVertex( newNode, shapeID ); break; default: mesh->SetNodeInVolume( newNode, shapeID ); } } //================================================================================ /* * Replace old nodes by new ones */ //================================================================================ void StdMeshers_RenumberHelper::DoReplaceNodes() { SMESH_MeshEditor( _mesh ).MergeNodes( _nodesToMerge ); } //============================================================================= /*! * Persistence */ //============================================================================= ostream & StdMeshers_BlockRenumber::SaveTo(ostream & save) { boost::archive::text_oarchive archive( save ); archive << *this; return save; } //============================================================================= /*! * Persistence */ //============================================================================= istream & StdMeshers_BlockRenumber::LoadFrom(istream & load) { SMESH_TRY; boost::archive::text_iarchive archive( load ); archive >> *this; SMESH_CATCH( SMESH::doNothing ); return load; } namespace boost { namespace serialization { //======================================================================= //function : serialize //purpose : serialize StdMeshers_BlockCS //======================================================================= template void serialize(Archive & ar, StdMeshers_BlockCS & blockCS, const unsigned int version) { ar & blockCS._solid; ar & blockCS._vertex000; ar & blockCS._vertex001; } } // namespace serialization } // namespace boost