// Copyright (C) 2007-2012 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. // // 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_Prism_3D.cxx // Module : SMESH // Created : Fri Oct 20 11:37:07 2006 // Author : Edward AGAPOV (eap) // #include "StdMeshers_Prism_3D.hxx" #include "StdMeshers_ProjectionUtils.hxx" #include "SMESH_MesherHelper.hxx" #include "SMDS_VolumeTool.hxx" #include "SMDS_VolumeOfNodes.hxx" #include "SMDS_EdgePosition.hxx" #include "SMESH_Comment.hxx" #include "utilities.h" #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; #define RETURN_BAD_RESULT(msg) { MESSAGE(")-: Error: " << msg); return false; } #define gpXYZ(n) gp_XYZ(n->X(),n->Y(),n->Z()) #define SHOWYXZ(msg, xyz) // {\ // gp_Pnt p (xyz); \ // cout << msg << " ("<< p.X() << "; " <upper_bound( parameter ); if ( u_col != columnsMap->begin() ) --u_col; return u_col; // return left column } //================================================================================ /*! * \brief Return nodes around given parameter and a ratio * \param column - node column * \param param - parameter * \param node1 - lower node * \param node2 - upper node * \retval double - ratio */ //================================================================================ double getRAndNodes( const TNodeColumn* column, const double param, const SMDS_MeshNode* & node1, const SMDS_MeshNode* & node2) { if ( param >= 1.0 || column->size() == 1) { node1 = node2 = column->back(); return 0; } int i = int( param * ( column->size() - 1 )); double u0 = double( i )/ double( column->size() - 1 ); double r = ( param - u0 ) * ( column->size() - 1 ); node1 = (*column)[ i ]; node2 = (*column)[ i + 1]; return r; } //================================================================================ /*! * \brief Compute boundary parameters of face parts * \param nbParts - nb of parts to split columns into * \param columnsMap - node columns of the face to split * \param params - computed parameters */ //================================================================================ void splitParams( const int nbParts, const TParam2ColumnMap* columnsMap, vector< double > & params) { params.clear(); params.reserve( nbParts + 1 ); TParam2ColumnIt last_par_col = --columnsMap->end(); double par = columnsMap->begin()->first; // 0. double parLast = last_par_col->first; params.push_back( par ); for ( int i = 0; i < nbParts - 1; ++ i ) { double partSize = ( parLast - par ) / double ( nbParts - i ); TParam2ColumnIt par_col = getColumn( columnsMap, par + partSize ); if ( par_col->first == par ) { ++par_col; if ( par_col == last_par_col ) { while ( i < nbParts - 1 ) params.push_back( par + partSize * i++ ); break; } } par = par_col->first; params.push_back( par ); } params.push_back( parLast ); // 1. } //================================================================================ /*! * \brief Return coordinate system for z-th layer of nodes */ //================================================================================ gp_Ax2 getLayerCoordSys(const int z, const vector< const TNodeColumn* >& columns, int& xColumn) { // gravity center of a layer gp_XYZ O(0,0,0); int vertexCol = -1; for ( int i = 0; i < columns.size(); ++i ) { O += gpXYZ( (*columns[ i ])[ z ]); if ( vertexCol < 0 && columns[ i ]->front()->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX ) vertexCol = i; } O /= columns.size(); // Z axis gp_Vec Z(0,0,0); int iPrev = columns.size()-1; for ( int i = 0; i < columns.size(); ++i ) { gp_Vec v1( O, gpXYZ( (*columns[ iPrev ])[ z ])); gp_Vec v2( O, gpXYZ( (*columns[ i ] )[ z ])); Z += v1 ^ v2; iPrev = i; } if ( vertexCol >= 0 ) { O = gpXYZ( (*columns[ vertexCol ])[ z ]); } if ( xColumn < 0 || xColumn >= columns.size() ) { // select a column for X dir double maxDist = 0; for ( int i = 0; i < columns.size(); ++i ) { double dist = ( O - gpXYZ((*columns[ i ])[ z ])).SquareModulus(); if ( dist > maxDist ) { xColumn = i; maxDist = dist; } } } // X axis gp_Vec X( O, gpXYZ( (*columns[ xColumn ])[ z ])); return gp_Ax2( O, Z, X); } //================================================================================ /*! * \brief Removes submeshes meshed with regular grid from given list * \retval int - nb of removed submeshes */ //================================================================================ int removeQuasiQuads(list< SMESH_subMesh* >& notQuadSubMesh) { int oldNbSM = notQuadSubMesh.size(); SMESHDS_Mesh* mesh = notQuadSubMesh.front()->GetFather()->GetMeshDS(); list< SMESH_subMesh* >::iterator smIt = notQuadSubMesh.begin(); #define __NEXT_SM { ++smIt; continue; } while ( smIt != notQuadSubMesh.end() ) { SMESH_subMesh* faceSm = *smIt; SMESHDS_SubMesh* faceSmDS = faceSm->GetSubMeshDS(); int nbQuads = faceSmDS->NbElements(); if ( nbQuads == 0 ) __NEXT_SM; // get oredered edges list< TopoDS_Edge > orderedEdges; list< int > nbEdgesInWires; TopoDS_Vertex V000; int nbWires = SMESH_Block::GetOrderedEdges( TopoDS::Face( faceSm->GetSubShape() ), V000, orderedEdges, nbEdgesInWires ); if ( nbWires != 1 || nbEdgesInWires.front() <= 4 ) __NEXT_SM; // get nb of segements on edges list nbSegOnEdge; list< TopoDS_Edge >::iterator edge = orderedEdges.begin(); for ( ; edge != orderedEdges.end(); ++edge ) { if ( SMESHDS_SubMesh* edgeSmDS = mesh->MeshElements( *edge )) nbSegOnEdge.push_back( edgeSmDS->NbElements() ); else nbSegOnEdge.push_back(0); } // unite nbSegOnEdge of continues edges int nbEdges = nbEdgesInWires.front(); list::iterator nbSegIt = nbSegOnEdge.begin(); for ( edge = orderedEdges.begin(); edge != orderedEdges.end(); ) { const TopoDS_Edge& e1 = *edge++; const TopoDS_Edge& e2 = ( edge == orderedEdges.end() ? orderedEdges.front() : *edge ); if ( SMESH_Algo::IsContinuous( e1, e2 )) { // common vertex of continues edges must be shared by two 2D mesh elems of geom face TopoDS_Vertex vCommon = TopExp::LastVertex( e1, true ); const SMDS_MeshNode* vNode = SMESH_Algo::VertexNode( vCommon, mesh ); int nbF = 0; if ( vNode ) { SMDS_ElemIteratorPtr fIt = vNode->GetInverseElementIterator(SMDSAbs_Face); while ( fIt->more() ) nbF += faceSmDS->Contains( fIt->next() ); } list::iterator nbSegIt1 = nbSegIt++; if ( !vNode || nbF == 2 ) // !vNode - two edges can be meshed as one { // unite if ( nbSegIt == nbSegOnEdge.end() ) nbSegIt = nbSegOnEdge.begin(); *nbSegIt += *nbSegIt1; nbSegOnEdge.erase( nbSegIt1 ); --nbEdges; } } else { ++nbSegIt; } } vector nbSegVec( nbSegOnEdge.begin(), nbSegOnEdge.end()); if ( nbSegVec.size() == 4 && nbSegVec[0] == nbSegVec[2] && nbSegVec[1] == nbSegVec[3] && nbSegVec[0] * nbSegVec[1] == nbQuads ) smIt = notQuadSubMesh.erase( smIt ); else __NEXT_SM; } return oldNbSM - notQuadSubMesh.size(); } } //======================================================================= //function : StdMeshers_Prism_3D //purpose : //======================================================================= StdMeshers_Prism_3D::StdMeshers_Prism_3D(int hypId, int studyId, SMESH_Gen* gen) :SMESH_3D_Algo(hypId, studyId, gen) { _name = "Prism_3D"; _shapeType = (1 << TopAbs_SHELL) | (1 << TopAbs_SOLID); // 1 bit per shape type myProjectTriangles = false; } //================================================================================ /*! * \brief Destructor */ //================================================================================ StdMeshers_Prism_3D::~StdMeshers_Prism_3D() {} //======================================================================= //function : CheckHypothesis //purpose : //======================================================================= bool StdMeshers_Prism_3D::CheckHypothesis(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape, SMESH_Hypothesis::Hypothesis_Status& aStatus) { // Check shape geometry /* PAL16229 aStatus = SMESH_Hypothesis::HYP_BAD_GEOMETRY; // find not quadrangle faces list< TopoDS_Shape > notQuadFaces; int nbEdge, nbWire, nbFace = 0; TopExp_Explorer exp( aShape, TopAbs_FACE ); for ( ; exp.More(); exp.Next() ) { ++nbFace; const TopoDS_Shape& face = exp.Current(); nbEdge = TAssocTool::Count( face, TopAbs_EDGE, 0 ); nbWire = TAssocTool::Count( face, TopAbs_WIRE, 0 ); if ( nbEdge!= 4 || nbWire!= 1 ) { if ( !notQuadFaces.empty() ) { if ( TAssocTool::Count( notQuadFaces.back(), TopAbs_EDGE, 0 ) != nbEdge || TAssocTool::Count( notQuadFaces.back(), TopAbs_WIRE, 0 ) != nbWire ) RETURN_BAD_RESULT("Different not quad faces"); } notQuadFaces.push_back( face ); } } if ( !notQuadFaces.empty() ) { if ( notQuadFaces.size() != 2 ) RETURN_BAD_RESULT("Bad nb not quad faces: " << notQuadFaces.size()); // check total nb faces nbEdge = TAssocTool::Count( notQuadFaces.back(), TopAbs_EDGE, 0 ); if ( nbFace != nbEdge + 2 ) RETURN_BAD_RESULT("Bad nb of faces: " << nbFace << " but must be " << nbEdge + 2); } */ // no hypothesis aStatus = SMESH_Hypothesis::HYP_OK; return true; } //======================================================================= //function : Compute //purpose : //======================================================================= bool StdMeshers_Prism_3D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theShape) { SMESH_MesherHelper helper( theMesh ); myHelper = &helper; myHelper->IsQuadraticSubMesh( theShape ); // Analyse mesh and geomerty to find block sub-shapes and submeshes if ( !myBlock.Init( myHelper, theShape )) return error( myBlock.GetError()); SMESHDS_Mesh* meshDS = theMesh.GetMeshDS(); int volumeID = meshDS->ShapeToIndex( theShape ); // To compute coordinates of a node inside a block, it is necessary to know // 1. normalized parameters of the node by which // 2. coordinates of node projections on all block sub-shapes are computed // So we fill projections on vertices at once as they are same for all nodes myShapeXYZ.resize( myBlock.NbSubShapes() ); for ( int iV = SMESH_Block::ID_FirstV; iV < SMESH_Block::ID_FirstE; ++iV ) { myBlock.VertexPoint( iV, myShapeXYZ[ iV ]); SHOWYXZ("V point " < trsf; if ( myBlock.GetLayersTransformation(trsf)) { // loop on nodes inside the bottom face TNode2ColumnMap::iterator bot_column = myBotToColumnMap.begin(); for ( ; bot_column != myBotToColumnMap.end(); ++bot_column ) { const TNode& tBotNode = bot_column->first; // bottom TNode if ( tBotNode.GetPositionType() != SMDS_TOP_FACE ) continue; // node is not inside face // column nodes; middle part of the column are zero pointers TNodeColumn& column = bot_column->second; TNodeColumn::iterator columnNodes = column.begin(); for ( int z = 0; columnNodes != column.end(); ++columnNodes, ++z) { const SMDS_MeshNode* & node = *columnNodes; if ( node ) continue; // skip bottom or top node gp_XYZ coords = tBotNode.GetCoords(); trsf[z-1].Transforms( coords ); node = meshDS->AddNode( coords.X(), coords.Y(), coords.Z() ); meshDS->SetNodeInVolume( node, volumeID ); } } // loop on bottom nodes } else // use block approach { // loop on nodes inside the bottom face TNode prevBNode; TNode2ColumnMap::iterator bot_column = myBotToColumnMap.begin(); for ( ; bot_column != myBotToColumnMap.end(); ++bot_column ) { const TNode& tBotNode = bot_column->first; // bottom TNode if ( tBotNode.GetPositionType() != SMDS_TOP_FACE ) continue; // node is not inside face // column nodes; middle part of the column are zero pointers TNodeColumn& column = bot_column->second; // compute bottom node parameters gp_XYZ paramHint(-1,-1,-1); if ( prevBNode.IsNeighbor( tBotNode )) paramHint = prevBNode.GetParams(); if ( !myBlock.ComputeParameters( tBotNode.GetCoords(), tBotNode.ChangeParams(), ID_BOT_FACE, paramHint )) return error(TCom("Can't compute normalized parameters for node ") << tBotNode.myNode->GetID() << " on the face #" << myBlock.SubMesh( ID_BOT_FACE )->GetId() ); prevBNode = tBotNode; myShapeXYZ[ ID_BOT_FACE ] = tBotNode.GetCoords(); gp_XYZ botParams = tBotNode.GetParams(); // compute top node parameters myShapeXYZ[ ID_TOP_FACE ] = gpXYZ( column.back() ); gp_XYZ topParams = botParams; topParams.SetZ( 1 ); if ( column.size() > 2 ) { gp_Pnt topCoords = myShapeXYZ[ ID_TOP_FACE ]; if ( !myBlock.ComputeParameters( topCoords, topParams, ID_TOP_FACE, topParams )) return error(TCom("Can't compute normalized parameters ") << "for node " << column.back()->GetID() << " on the face #"<< column.back()->getshapeId() ); } // vertical loop TNodeColumn::iterator columnNodes = column.begin(); for ( int z = 0; columnNodes != column.end(); ++columnNodes, ++z) { const SMDS_MeshNode* & node = *columnNodes; if ( node ) continue; // skip bottom or top node // params of a node to create double rz = (double) z / (double) ( column.size() - 1 ); gp_XYZ params = botParams * ( 1 - rz ) + topParams * rz; // set coords on all faces and nodes const int nbSideFaces = 4; int sideFaceIDs[nbSideFaces] = { SMESH_Block::ID_Fx0z, SMESH_Block::ID_Fx1z, SMESH_Block::ID_F0yz, SMESH_Block::ID_F1yz }; for ( int iF = 0; iF < nbSideFaces; ++iF ) if ( !setFaceAndEdgesXYZ( sideFaceIDs[ iF ], params, z )) return false; // compute coords for a new node gp_XYZ coords; if ( !SMESH_Block::ShellPoint( params, myShapeXYZ, coords )) return error("Can't compute coordinates by normalized parameters"); SHOWYXZ("TOPFacePoint ",myShapeXYZ[ ID_TOP_FACE]); SHOWYXZ("BOT Node "<< tBotNode.myNode->GetID(),gpXYZ(tBotNode.myNode)); SHOWYXZ("ShellPoint ",coords); // create a node node = meshDS->AddNode( coords.X(), coords.Y(), coords.Z() ); meshDS->SetNodeInVolume( node, volumeID ); } } // loop on bottom nodes } // Create volumes SMESHDS_SubMesh* smDS = myBlock.SubMeshDS( ID_BOT_FACE ); if ( !smDS ) return error(COMPERR_BAD_INPUT_MESH, "Null submesh"); // loop on bottom mesh faces SMDS_ElemIteratorPtr faceIt = smDS->GetElements(); while ( faceIt->more() ) { const SMDS_MeshElement* face = faceIt->next(); if ( !face || face->GetType() != SMDSAbs_Face ) continue; int nbNodes = face->NbNodes(); if ( face->IsQuadratic() ) nbNodes /= 2; // find node columns for each node vector< const TNodeColumn* > columns( nbNodes ); for ( int i = 0; i < nbNodes; ++i ) { const SMDS_MeshNode* n = face->GetNode( i ); if ( n->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE ) { TNode2ColumnMap::iterator bot_column = myBotToColumnMap.find( n ); if ( bot_column == myBotToColumnMap.end() ) return error(TCom("No nodes found above node ") << n->GetID() ); columns[ i ] = & bot_column->second; } else { columns[ i ] = myBlock.GetNodeColumn( n ); if ( !columns[ i ] ) return error(TCom("No side nodes found above node ") << n->GetID() ); } } // create prisms AddPrisms( columns, myHelper ); } // loop on bottom mesh faces // clear data myBotToColumnMap.clear(); myBlock.Clear(); return true; } //======================================================================= //function : Evaluate //purpose : //======================================================================= bool StdMeshers_Prism_3D::Evaluate(SMESH_Mesh& theMesh, const TopoDS_Shape& theShape, MapShapeNbElems& aResMap) { // find face contains only triangles vector < SMESH_subMesh * >meshFaces; TopTools_SequenceOfShape aFaces; int NumBase = 0, i = 0, NbQFs = 0; for (TopExp_Explorer exp(theShape, TopAbs_FACE); exp.More(); exp.Next()) { i++; aFaces.Append(exp.Current()); SMESH_subMesh *aSubMesh = theMesh.GetSubMesh(exp.Current()); meshFaces.push_back(aSubMesh); MapShapeNbElemsItr anIt = aResMap.find(meshFaces[i-1]); if( anIt==aResMap.end() ) { SMESH_ComputeErrorPtr& smError = aSubMesh->GetComputeError(); smError.reset( new SMESH_ComputeError(COMPERR_ALGO_FAILED,"Submesh can not be evaluated",this)); return false; } std::vector aVec = (*anIt).second; int nbtri = Max(aVec[SMDSEntity_Triangle],aVec[SMDSEntity_Quad_Triangle]); int nbqua = Max(aVec[SMDSEntity_Quadrangle],aVec[SMDSEntity_Quad_Quadrangle]); if( nbtri==0 && nbqua>0 ) { NbQFs++; } if( nbtri>0 ) { NumBase = i; } } if(NbQFs<4) { std::vector aResVec(SMDSEntity_Last); for(int i=SMDSEntity_Node; iGetComputeError(); smError.reset( new SMESH_ComputeError(COMPERR_ALGO_FAILED,"Submesh can not be evaluated",this)); return false; } if(NumBase==0) NumBase = 1; // only quads => set 1 faces as base // find number of 1d elems for base face int nb1d = 0; TopTools_MapOfShape Edges1; for (TopExp_Explorer exp(aFaces.Value(NumBase), TopAbs_EDGE); exp.More(); exp.Next()) { Edges1.Add(exp.Current()); SMESH_subMesh *sm = theMesh.GetSubMesh(exp.Current()); if( sm ) { MapShapeNbElemsItr anIt = aResMap.find(sm); if( anIt == aResMap.end() ) continue; std::vector aVec = (*anIt).second; nb1d += Max(aVec[SMDSEntity_Edge],aVec[SMDSEntity_Quad_Edge]); } } // find face opposite to base face int OppNum = 0; for(i=1; i<=6; i++) { if(i==NumBase) continue; bool IsOpposite = true; for(TopExp_Explorer exp(aFaces.Value(i), TopAbs_EDGE); exp.More(); exp.Next()) { if( Edges1.Contains(exp.Current()) ) { IsOpposite = false; break; } } if(IsOpposite) { OppNum = i; break; } } // find number of 2d elems on side faces int nb2d = 0; for(i=1; i<=6; i++) { if( i==OppNum || i==NumBase ) continue; MapShapeNbElemsItr anIt = aResMap.find( meshFaces[i-1] ); if( anIt == aResMap.end() ) continue; std::vector aVec = (*anIt).second; nb2d += Max(aVec[SMDSEntity_Quadrangle],aVec[SMDSEntity_Quad_Quadrangle]); } MapShapeNbElemsItr anIt = aResMap.find( meshFaces[NumBase-1] ); std::vector aVec = (*anIt).second; bool IsQuadratic = (aVec[SMDSEntity_Quad_Triangle]>aVec[SMDSEntity_Triangle]) || (aVec[SMDSEntity_Quad_Quadrangle]>aVec[SMDSEntity_Quadrangle]); int nb2d_face0_3 = Max(aVec[SMDSEntity_Triangle],aVec[SMDSEntity_Quad_Triangle]); int nb2d_face0_4 = Max(aVec[SMDSEntity_Quadrangle],aVec[SMDSEntity_Quad_Quadrangle]); int nb0d_face0 = aVec[SMDSEntity_Node]; int nb1d_face0_int = ( nb2d_face0_3*3 + nb2d_face0_4*4 - nb1d ) / 2; std::vector aResVec(SMDSEntity_Last); for(int i=SMDSEntity_Node; i & columns, SMESH_MesherHelper* helper) { int nbNodes = columns.size(); int nbZ = columns[0]->size(); if ( nbZ < 2 ) return; // find out orientation bool isForward = true; SMDS_VolumeTool vTool; int z = 1; switch ( nbNodes ) { case 3: { SMDS_VolumeOfNodes tmpPenta ( (*columns[0])[z-1], // bottom (*columns[1])[z-1], (*columns[2])[z-1], (*columns[0])[z], // top (*columns[1])[z], (*columns[2])[z] ); vTool.Set( &tmpPenta ); isForward = vTool.IsForward(); break; } case 4: { SMDS_VolumeOfNodes tmpHex( (*columns[0])[z-1], (*columns[1])[z-1], // bottom (*columns[2])[z-1], (*columns[3])[z-1], (*columns[0])[z], (*columns[1])[z], // top (*columns[2])[z], (*columns[3])[z] ); vTool.Set( &tmpHex ); isForward = vTool.IsForward(); break; } default: const int di = (nbNodes+1) / 3; SMDS_VolumeOfNodes tmpVol ( (*columns[0] )[z-1], (*columns[di] )[z-1], (*columns[2*di])[z-1], (*columns[0] )[z], (*columns[di] )[z], (*columns[2*di])[z] ); vTool.Set( &tmpVol ); isForward = vTool.IsForward(); } // vertical loop on columns helper->SetElementsOnShape( true ); switch ( nbNodes ) { case 3: { // ---------- pentahedra const int i1 = isForward ? 1 : 2; const int i2 = isForward ? 2 : 1; for ( z = 1; z < nbZ; ++z ) helper->AddVolume( (*columns[0 ])[z-1], // bottom (*columns[i1])[z-1], (*columns[i2])[z-1], (*columns[0 ])[z], // top (*columns[i1])[z], (*columns[i2])[z] ); break; } case 4: { // ---------- hexahedra const int i1 = isForward ? 1 : 3; const int i3 = isForward ? 3 : 1; for ( z = 1; z < nbZ; ++z ) helper->AddVolume( (*columns[0])[z-1], (*columns[i1])[z-1], // bottom (*columns[2])[z-1], (*columns[i3])[z-1], (*columns[0])[z], (*columns[i1])[z], // top (*columns[2])[z], (*columns[i3])[z] ); break; } case 6: { // ---------- octahedra const int iBase1 = isForward ? -1 : 0; const int iBase2 = isForward ? 0 :-1; for ( z = 1; z < nbZ; ++z ) helper->AddVolume( (*columns[0])[z+iBase1], (*columns[1])[z+iBase1], // bottom or top (*columns[2])[z+iBase1], (*columns[3])[z+iBase1], (*columns[4])[z+iBase1], (*columns[5])[z+iBase1], (*columns[0])[z+iBase2], (*columns[1])[z+iBase2], // top or bottom (*columns[2])[z+iBase2], (*columns[3])[z+iBase2], (*columns[4])[z+iBase2], (*columns[5])[z+iBase2] ); break; } default: // ---------- polyhedra vector quantities( 2 + nbNodes, 4 ); quantities[0] = quantities[1] = nbNodes; columns.resize( nbNodes + 1 ); columns[ nbNodes ] = columns[ 0 ]; const int i1 = isForward ? 1 : 3; const int i3 = isForward ? 3 : 1; const int iBase1 = isForward ? -1 : 0; const int iBase2 = isForward ? 0 :-1; vector nodes( 2*nbNodes + 4*nbNodes); for ( z = 1; z < nbZ; ++z ) { for ( int i = 0; i < nbNodes; ++i ) { nodes[ i ] = (*columns[ i ])[z+iBase1]; // bottom or top nodes[ 2*nbNodes-i-1 ] = (*columns[ i ])[z+iBase2]; // top or bottom // side int di = 2*nbNodes + 4*i; nodes[ di+0 ] = (*columns[i ])[z ]; nodes[ di+i1] = (*columns[i+1])[z ]; nodes[ di+2 ] = (*columns[i+1])[z-1]; nodes[ di+i3] = (*columns[i ])[z-1]; } helper->AddPolyhedralVolume( nodes, quantities ); } } // switch ( nbNodes ) } //================================================================================ /*! * \brief Find correspondence between bottom and top nodes * If elements on the bottom and top faces are topologically different, * and projection is possible and allowed, perform the projection * \retval bool - is a success or not */ //================================================================================ bool StdMeshers_Prism_3D::assocOrProjBottom2Top() { SMESH_subMesh * botSM = myBlock.SubMesh( ID_BOT_FACE ); SMESH_subMesh * topSM = myBlock.SubMesh( ID_TOP_FACE ); SMESHDS_SubMesh * botSMDS = botSM->GetSubMeshDS(); SMESHDS_SubMesh * topSMDS = topSM->GetSubMeshDS(); if ( !botSMDS || botSMDS->NbElements() == 0 ) return error(TCom("No elememts on face #") << botSM->GetId()); bool needProject = false; if ( !topSMDS || botSMDS->NbElements() != topSMDS->NbElements() || botSMDS->NbNodes() != topSMDS->NbNodes()) { MESSAGE("nb elem bot " << botSMDS->NbElements() << " top " << topSMDS->NbElements()); MESSAGE("nb node bot " << botSMDS->NbNodes() << " top " << topSMDS->NbNodes()); if ( myBlock.HasNotQuadElemOnTop() ) return error(TCom("Mesh on faces #") << botSM->GetId() <<" and #"<< topSM->GetId() << " seems different" ); needProject = true; } if ( 0/*needProject && !myProjectTriangles*/ ) return error(TCom("Mesh on faces #") << botSM->GetId() <<" and #"<< topSM->GetId() << " seems different" ); ///RETURN_BAD_RESULT("Need to project but not allowed"); if ( needProject ) { return projectBottomToTop(); } TopoDS_Face botFace = TopoDS::Face( myBlock.Shape( ID_BOT_FACE )); TopoDS_Face topFace = TopoDS::Face( myBlock.Shape( ID_TOP_FACE )); // associate top and bottom faces TAssocTool::TShapeShapeMap shape2ShapeMap; if ( !TAssocTool::FindSubShapeAssociation( botFace, myBlock.Mesh(), topFace, myBlock.Mesh(), shape2ShapeMap) ) return error(TCom("Topology of faces #") << botSM->GetId() <<" and #"<< topSM->GetId() << " seems different" ); // Find matching nodes of top and bottom faces TNodeNodeMap n2nMap; if ( ! TAssocTool::FindMatchingNodesOnFaces( botFace, myBlock.Mesh(), topFace, myBlock.Mesh(), shape2ShapeMap, n2nMap )) return error(TCom("Mesh on faces #") << botSM->GetId() <<" and #"<< topSM->GetId() << " seems different" ); // Fill myBotToColumnMap int zSize = myBlock.VerticalSize(); //TNode prevTNode; TNodeNodeMap::iterator bN_tN = n2nMap.begin(); for ( ; bN_tN != n2nMap.end(); ++bN_tN ) { const SMDS_MeshNode* botNode = bN_tN->first; const SMDS_MeshNode* topNode = bN_tN->second; if ( botNode->GetPosition()->GetTypeOfPosition() != SMDS_TOP_FACE ) continue; // wall columns are contained in myBlock // create node column TNode bN( botNode ); TNode2ColumnMap::iterator bN_col = myBotToColumnMap.insert( make_pair ( bN, TNodeColumn() )).first; TNodeColumn & column = bN_col->second; column.resize( zSize ); column.front() = botNode; column.back() = topNode; } return true; } //================================================================================ /*! * \brief Remove quadrangles from the top face and * create triangles there by projection from the bottom * \retval bool - a success or not */ //================================================================================ bool StdMeshers_Prism_3D::projectBottomToTop() { SMESH_subMesh * botSM = myBlock.SubMesh( ID_BOT_FACE ); SMESH_subMesh * topSM = myBlock.SubMesh( ID_TOP_FACE ); SMESHDS_SubMesh * botSMDS = botSM->GetSubMeshDS(); SMESHDS_SubMesh * topSMDS = topSM->GetSubMeshDS(); if ( topSMDS ) topSM->ComputeStateEngine( SMESH_subMesh::CLEAN ); SMESHDS_Mesh* meshDS = myBlock.MeshDS(); int shapeID = myHelper->GetSubShapeID(); int topFaceID = meshDS->ShapeToIndex( topSM->GetSubShape() ); // Fill myBotToColumnMap int zSize = myBlock.VerticalSize(); TNode prevTNode; SMDS_NodeIteratorPtr nIt = botSMDS->GetNodes(); while ( nIt->more() ) { const SMDS_MeshNode* botNode = nIt->next(); if ( botNode->GetPosition()->GetTypeOfPosition() != SMDS_TOP_FACE ) continue; // strange // compute bottom node params TNode bN( botNode ); gp_XYZ paramHint(-1,-1,-1); if ( prevTNode.IsNeighbor( bN )) paramHint = prevTNode.GetParams(); if ( !myBlock.ComputeParameters( bN.GetCoords(), bN.ChangeParams(), ID_BOT_FACE, paramHint )) return error(TCom("Can't compute normalized parameters for node ") << botNode->GetID() << " on the face #"<< botSM->GetId() ); prevTNode = bN; // compute top node coords gp_XYZ topXYZ; gp_XY topUV; if ( !myBlock.FacePoint( ID_TOP_FACE, bN.GetParams(), topXYZ ) || !myBlock.FaceUV ( ID_TOP_FACE, bN.GetParams(), topUV )) return error(TCom("Can't compute coordinates " "by normalized parameters on the face #")<< topSM->GetId() ); SMDS_MeshNode * topNode = meshDS->AddNode( topXYZ.X(),topXYZ.Y(),topXYZ.Z() ); meshDS->SetNodeOnFace( topNode, topFaceID, topUV.X(), topUV.Y() ); // create node column TNode2ColumnMap::iterator bN_col = myBotToColumnMap.insert( make_pair ( bN, TNodeColumn() )).first; TNodeColumn & column = bN_col->second; column.resize( zSize ); column.front() = botNode; column.back() = topNode; } // Create top faces // loop on bottom mesh faces SMDS_ElemIteratorPtr faceIt = botSMDS->GetElements(); while ( faceIt->more() ) { const SMDS_MeshElement* face = faceIt->next(); if ( !face || face->GetType() != SMDSAbs_Face ) continue; int nbNodes = face->NbNodes(); if ( face->IsQuadratic() ) nbNodes /= 2; // find top node in columns for each bottom node vector< const SMDS_MeshNode* > nodes( nbNodes ); for ( int i = 0; i < nbNodes; ++i ) { const SMDS_MeshNode* n = face->GetNode( nbNodes - i - 1 ); if ( n->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE ) { TNode2ColumnMap::iterator bot_column = myBotToColumnMap.find( n ); if ( bot_column == myBotToColumnMap.end() ) return error(TCom("No nodes found above node ") << n->GetID() ); nodes[ i ] = bot_column->second.back(); } else { const TNodeColumn* column = myBlock.GetNodeColumn( n ); if ( !column ) return error(TCom("No side nodes found above node ") << n->GetID() ); nodes[ i ] = column->back(); } } // create a face, with reversed orientation SMDS_MeshElement* newFace = 0; switch ( nbNodes ) { case 3: { newFace = myHelper->AddFace(nodes[0], nodes[1], nodes[2]); break; } case 4: { newFace = myHelper->AddFace( nodes[0], nodes[1], nodes[2], nodes[3] ); break; } default: newFace = meshDS->AddPolygonalFace( nodes ); } if ( newFace && shapeID > 0 ) meshDS->SetMeshElementOnShape( newFace, shapeID ); } return true; } //================================================================================ /*! * \brief Set projection coordinates of a node to a face and it's sub-shapes * \param faceID - the face given by in-block ID * \param params - node normalized parameters * \retval bool - is a success */ //================================================================================ bool StdMeshers_Prism_3D::setFaceAndEdgesXYZ( const int faceID, const gp_XYZ& params, int z ) { // find base and top edges of the face enum { BASE = 0, TOP, LEFT, RIGHT }; vector< int > edgeVec; // 0-base, 1-top SMESH_Block::GetFaceEdgesIDs( faceID, edgeVec ); myBlock.EdgePoint( edgeVec[ BASE ], params, myShapeXYZ[ edgeVec[ BASE ]]); myBlock.EdgePoint( edgeVec[ TOP ], params, myShapeXYZ[ edgeVec[ TOP ]]); SHOWYXZ("\nparams ", params); SHOWYXZ("TOP is " <GetInverseElementIterator(SMDSAbs_Face); while ( fIt->more() ) if ( fIt->next()->GetNodeIndex( myNode ) >= 0 ) return true; return false; } //================================================================================ /*! * \brief Constructor. Initialization is needed */ //================================================================================ StdMeshers_PrismAsBlock::StdMeshers_PrismAsBlock() { mySide = 0; } StdMeshers_PrismAsBlock::~StdMeshers_PrismAsBlock() { Clear(); } void StdMeshers_PrismAsBlock::Clear() { myHelper = 0; myShapeIDMap.Clear(); myError.reset(); if ( mySide ) { delete mySide; mySide = 0; } myParam2ColumnMaps.clear(); myShapeIndex2ColumnMap.clear(); } //================================================================================ /*! * \brief Initialization. * \param helper - helper loaded with mesh and 3D shape * \param shape3D - a closed shell or solid * \retval bool - false if a mesh or a shape are KO */ //================================================================================ bool StdMeshers_PrismAsBlock::Init(SMESH_MesherHelper* helper, const TopoDS_Shape& shape3D) { if ( mySide ) { delete mySide; mySide = 0; } vector< TSideFace* > sideFaces( NB_WALL_FACES, 0 ); vector< pair< double, double> > params ( NB_WALL_FACES ); mySide = new TSideFace( sideFaces, params ); myHelper = helper; SMESHDS_Mesh* meshDS = myHelper->GetMeshDS(); SMESH_Block::init(); myShapeIDMap.Clear(); myShapeIndex2ColumnMap.clear(); int wallFaceIds[ NB_WALL_FACES ] = { // to walk around a block SMESH_Block::ID_Fx0z, SMESH_Block::ID_F1yz, SMESH_Block::ID_Fx1z, SMESH_Block::ID_F0yz }; myError = SMESH_ComputeError::New(); // ------------------------------------------------------------- // Look for top and bottom faces: not quadrangle ones or meshed // with not quadrangle elements // ------------------------------------------------------------- list< SMESH_subMesh* > notQuadGeomSubMesh; list< SMESH_subMesh* > notQuadElemSubMesh; int nbFaces = 0; // SMESH_subMesh* mainSubMesh = myHelper->GetMesh()->GetSubMeshContaining( shape3D ); if ( !mainSubMesh ) return error(COMPERR_BAD_INPUT_MESH,"Null submesh of shape3D"); // analyse face submeshes SMESH_subMeshIteratorPtr smIt = mainSubMesh->getDependsOnIterator(false,false); while ( smIt->more() ) { SMESH_subMesh* sm = smIt->next(); const TopoDS_Shape& face = sm->GetSubShape(); if ( face.ShapeType() != TopAbs_FACE ) continue; nbFaces++; // is quadrangle face? list< TopoDS_Edge > orderedEdges; list< int > nbEdgesInWires; TopoDS_Vertex V000; int nbWires = GetOrderedEdges( TopoDS::Face( face ), V000, orderedEdges, nbEdgesInWires ); if ( nbWires != 1 || nbEdgesInWires.front() != 4 ) notQuadGeomSubMesh.push_back( sm ); // look for not quadrangle mesh elements if ( SMESHDS_SubMesh* smDS = sm->GetSubMeshDS() ) { bool hasNotQuad = false; SMDS_ElemIteratorPtr eIt = smDS->GetElements(); while ( eIt->more() && !hasNotQuad ) { const SMDS_MeshElement* elem = eIt->next(); if ( elem->GetType() == SMDSAbs_Face ) { int nbNodes = elem->NbNodes(); if ( elem->IsQuadratic() ) nbNodes /= 2; hasNotQuad = ( nbNodes != 4 ); } } if ( hasNotQuad ) notQuadElemSubMesh.push_back( sm ); } else { return error(COMPERR_BAD_INPUT_MESH,TCom("Not meshed face #")<GetId()); } // check if a quadrangle face is meshed with a quadranglar grid if ( notQuadGeomSubMesh.back() != sm && notQuadElemSubMesh.back() != sm ) { // count nb edges on face sides vector< int > nbEdges; nbEdges.reserve( nbEdgesInWires.front() ); for ( list< TopoDS_Edge >::iterator edge = orderedEdges.begin(); edge != orderedEdges.end(); ++edge ) { if ( SMESHDS_SubMesh* smDS = meshDS->MeshElements( *edge )) nbEdges.push_back ( smDS->NbElements() ); else nbEdges.push_back ( 0 ); } int nbQuads = sm->GetSubMeshDS()->NbElements(); if ( nbEdges[0] * nbEdges[1] != nbQuads || nbEdges[0] != nbEdges[2] || nbEdges[1] != nbEdges[3] ) notQuadElemSubMesh.push_back( sm ); } } // ---------------------------------------------------------------------- // Analyse mesh and topology of faces: choose the bottom submesh. // If there are not quadrangle geom faces, they are top and bottom ones. // Not quadrangle geom faces must be only on top and bottom. // ---------------------------------------------------------------------- SMESH_subMesh * botSM = 0; SMESH_subMesh * topSM = 0; int nbNotQuad = notQuadGeomSubMesh.size(); int nbNotQuadMeshed = notQuadElemSubMesh.size(); bool hasNotQuad = ( nbNotQuad || nbNotQuadMeshed ); // detect bad cases if ( nbNotQuadMeshed > 2 ) { return error(COMPERR_BAD_INPUT_MESH, TCom("More than 2 faces with not quadrangle elements: ") < 0 && nbNotQuad != 2 ) { // Issue 0020843 - one of side faces is quasi-quadrilateral. // Remove from notQuadGeomSubMesh faces meshed with regular grid nbQuasiQuads = removeQuasiQuads( notQuadGeomSubMesh ); nbNotQuad -= nbQuasiQuads; if ( nbNotQuad > 0 && nbNotQuad != 2 ) return error(COMPERR_BAD_SHAPE, TCom("More than 2 not quadrilateral faces: ") < 0 ) botSM = notQuadElemSubMesh.front(); else botSM = notQuadGeomSubMesh.front(); if ( nbNotQuadMeshed > 1 ) topSM = notQuadElemSubMesh.back(); else if ( nbNotQuad > 1 ) topSM = notQuadGeomSubMesh.back(); } // detect other bad cases if ( nbNotQuad == 2 && nbNotQuadMeshed > 0 ) { bool ok = false; if ( nbNotQuadMeshed == 1 ) ok = ( find( notQuadGeomSubMesh.begin(), notQuadGeomSubMesh.end(), botSM ) != notQuadGeomSubMesh.end() ); else ok = ( notQuadGeomSubMesh == notQuadElemSubMesh ); if ( !ok ) return error(COMPERR_BAD_INPUT_MESH, "Side face meshed with not quadrangle elements"); } myNotQuadOnTop = ( nbNotQuadMeshed > 1 ); MESSAGE("myNotQuadOnTop " << myNotQuadOnTop << " nbNotQuadMeshed " << nbNotQuadMeshed); // ---------------------------------------------------------- if ( nbNotQuad == 0 ) // Standard block of 6 quadrangle faces ? { // SMESH_Block will perform geometry analysis, we need just to find 2 // connected vertices on top and bottom TopoDS_Vertex Vbot, Vtop; if ( nbNotQuadMeshed > 0 ) // Look for vertices { TopTools_IndexedMapOfShape edgeMap; TopExp::MapShapes( botSM->GetSubShape(), TopAbs_EDGE, edgeMap ); // vertex 1 is any vertex of the bottom face Vbot = TopExp::FirstVertex( TopoDS::Edge( edgeMap( 1 ))); // vertex 2 is end vertex of edge sharing Vbot and not belonging to the bottom face TopTools_ListIteratorOfListOfShape ancestIt = Mesh()->GetAncestors( Vbot ); for ( ; Vtop.IsNull() && ancestIt.More(); ancestIt.Next() ) { const TopoDS_Shape & ancestor = ancestIt.Value(); if ( ancestor.ShapeType() == TopAbs_EDGE && !edgeMap.FindIndex( ancestor )) { TopoDS_Vertex V1, V2; TopExp::Vertices( TopoDS::Edge( ancestor ), V1, V2); if ( Vbot.IsSame ( V1 )) Vtop = V2; else if ( Vbot.IsSame ( V2 )) Vtop = V1; // check that Vtop belongs to shape3D TopExp_Explorer exp( shape3D, TopAbs_VERTEX ); for ( ; exp.More(); exp.Next() ) if ( Vtop.IsSame( exp.Current() )) break; if ( !exp.More() ) Vtop.Nullify(); } } } // get shell from shape3D TopoDS_Shell shell; TopExp_Explorer exp( shape3D, TopAbs_SHELL ); int nbShell = 0; for ( ; exp.More(); exp.Next(), ++nbShell ) shell = TopoDS::Shell( exp.Current() ); // if ( nbShell != 1 ) // RETURN_BAD_RESULT("There must be 1 shell in the block"); // Load geometry in SMESH_Block if ( !SMESH_Block::FindBlockShapes( shell, Vbot, Vtop, myShapeIDMap )) { if ( !hasNotQuad ) return error(COMPERR_BAD_SHAPE, "Can't detect top and bottom of a prism"); } else { if ( !botSM ) botSM = Mesh()->GetSubMeshContaining( myShapeIDMap( ID_BOT_FACE )); if ( !topSM ) topSM = Mesh()->GetSubMeshContaining( myShapeIDMap( ID_TOP_FACE )); } } // end Standard block of 6 quadrangle faces // -------------------------------------------------------- // Here the top and bottom faces are found if ( nbNotQuadMeshed == 2 ) // roughly check correspondence of horiz meshes { // SMESHDS_SubMesh* topSMDS = topSM->GetSubMeshDS(); // SMESHDS_SubMesh* botSMDS = botSM->GetSubMeshDS(); // if ( topSMDS->NbNodes() != botSMDS->NbNodes() || // topSMDS->NbElements() != botSMDS->NbElements() ) // RETURN_BAD_RESULT("Top mesh doesn't correspond to bottom one"); } // --------------------------------------------------------- // If there are not quadrangle geom faces, we emulate // a block of 6 quadrangle faces. // Load SMESH_Block with faces and edges geometry // --------------------------------------------------------- // find vertex 000 - the one with smallest coordinates (for easy DEBUG :-) TopoDS_Vertex V000; double minVal = DBL_MAX, minX, val; for ( TopExp_Explorer exp( botSM->GetSubShape(), TopAbs_VERTEX ); exp.More(); exp.Next() ) { const TopoDS_Vertex& v = TopoDS::Vertex( exp.Current() ); gp_Pnt P = BRep_Tool::Pnt( v ); val = P.X() + P.Y() + P.Z(); if ( val < minVal || ( val == minVal && P.X() < minX )) { V000 = v; minVal = val; minX = P.X(); } } // Get ordered bottom edges list< TopoDS_Edge > orderedEdges; list< int > nbEInW; SMESH_Block::GetOrderedEdges( TopoDS::Face( botSM->GetSubShape().Reversed() ), V000, orderedEdges, nbEInW ); // if ( nbEInW.size() != 1 ) // RETURN_BAD_RESULT("Wrong prism geometry"); // Get Wall faces corresponding to the ordered bottom edges list< TopoDS_Face > wallFaces; if ( !GetWallFaces( Mesh(), shape3D, botSM->GetSubShape(), orderedEdges, nbEInW, wallFaces)) return error(COMPERR_BAD_SHAPE, "Can't find side faces"); // check that the found top and bottom faces are opposite { for (TopExp_Explorer edge(botSM->GetSubShape(), TopAbs_EDGE); edge.More(); edge.Next()) if ( helper->IsSubShape( edge.Current(), topSM->GetSubShape() )) return error(notQuadGeomSubMesh.empty() ? COMPERR_BAD_INPUT_MESH : COMPERR_BAD_SHAPE, "Non-quadrilateral faces are not opposite"); } // Protect from a distorted block (test 3D_mesh_HEXA3D/B7 on 32bit platform) // check that all wall faces have an edge common with the top face { list< TopoDS_Face >::iterator faceIt = wallFaces.begin(); for ( ; faceIt != wallFaces.end(); ++faceIt ) { bool hasCommon = false; for (TopExp_Explorer edge(*faceIt, TopAbs_EDGE); !hasCommon && edge.More(); edge.Next()) if ( helper->IsSubShape( edge.Current(), topSM->GetSubShape() )) hasCommon = true; if ( !hasCommon ) return error(COMPERR_BAD_SHAPE); } } // Find columns of wall nodes and calculate edges' lengths // -------------------------------------------------------- myParam2ColumnMaps.clear(); myParam2ColumnMaps.resize( orderedEdges.size() ); // total nb edges int iE, nbEdges = nbEInW.front(); // nb outer edges vector< double > edgeLength( nbEdges ); map< double, int > len2edgeMap; list< TopoDS_Edge >::iterator edgeIt = orderedEdges.begin(); list< TopoDS_Face >::iterator faceIt = wallFaces.begin(); for ( iE = 0; iE < nbEdges; ++edgeIt, ++faceIt ) { TParam2ColumnMap & faceColumns = myParam2ColumnMaps[ iE ]; if ( !myHelper->LoadNodeColumns( faceColumns, *faceIt, *edgeIt, meshDS )) return error(COMPERR_BAD_INPUT_MESH, TCom("Can't find regular quadrangle mesh ") << "on a side face #" << MeshDS()->ShapeToIndex( *faceIt )); SHOWYXZ("\np1 F "<second.front() )); SHOWYXZ("p2 F "<second.front() )); SHOWYXZ("V First "<MeshElements( *edgeIt); if ( !smDS ) return error(COMPERR_BAD_INPUT_MESH, TCom("Null submesh on the edge #") << MeshDS()->ShapeToIndex( *edgeIt )); // assure length uniqueness edgeLength[ iE ] *= smDS->NbNodes() + edgeLength[ iE ] / ( 1000 + iE ); len2edgeMap[ edgeLength[ iE ]] = iE; } ++iE; } // Load columns of internal edges (forming holes) // and fill map ShapeIndex to TParam2ColumnMap for them for ( ; edgeIt != orderedEdges.end() ; ++edgeIt, ++faceIt ) { TParam2ColumnMap & faceColumns = myParam2ColumnMaps[ iE ]; if ( !myHelper->LoadNodeColumns( faceColumns, *faceIt, *edgeIt, meshDS )) return error(COMPERR_BAD_INPUT_MESH, TCom("Can't find regular quadrangle mesh ") << "on a side face #" << MeshDS()->ShapeToIndex( *faceIt )); // edge columns int id = MeshDS()->ShapeToIndex( *edgeIt ); bool isForward = true; // meaningless for intenal wires myShapeIndex2ColumnMap[ id ] = make_pair( & faceColumns, isForward ); // columns for vertices // 1 const SMDS_MeshNode* n0 = faceColumns.begin()->second.front(); id = n0->getshapeId(); myShapeIndex2ColumnMap[ id ] = make_pair( & faceColumns, isForward ); // 2 const SMDS_MeshNode* n1 = faceColumns.rbegin()->second.front(); id = n1->getshapeId(); myShapeIndex2ColumnMap[ id ] = make_pair( & faceColumns, isForward ); // SHOWYXZ("\np1 F "<second.front() )); // SHOWYXZ("p2 F "<second.front() )); // SHOWYXZ("V First "< iE2nbSplit; if ( nbEdges != NB_WALL_FACES ) // define how to split { if ( len2edgeMap.size() != nbEdges ) RETURN_BAD_RESULT("Uniqueness of edge lengths not assured"); map< double, int >::reverse_iterator maxLen_i = len2edgeMap.rbegin(); map< double, int >::reverse_iterator midLen_i = ++len2edgeMap.rbegin(); double maxLen = maxLen_i->first; double midLen = ( len2edgeMap.size() == 1 ) ? 0 : midLen_i->first; switch ( nbEdges ) { case 1: // 0-th edge is split into 4 parts iE2nbSplit.insert( make_pair( 0, 4 )); break; case 2: // either the longest edge is split into 3 parts, or both edges into halves if ( maxLen / 3 > midLen / 2 ) { iE2nbSplit.insert( make_pair( maxLen_i->second, 3 )); } else { iE2nbSplit.insert( make_pair( maxLen_i->second, 2 )); iE2nbSplit.insert( make_pair( midLen_i->second, 2 )); } break; case 3: // split longest into halves iE2nbSplit.insert( make_pair( maxLen_i->second, 2 )); } } // Create TSideFace's faceIt = wallFaces.begin(); edgeIt = orderedEdges.begin(); int iSide = 0; for ( iE = 0; iE < nbEdges; ++edgeIt, ++faceIt ) { // split? map< int, int >::iterator i_nb = iE2nbSplit.find( iE ); if ( i_nb != iE2nbSplit.end() ) { // split! int nbSplit = i_nb->second; vector< double > params; splitParams( nbSplit, &myParam2ColumnMaps[ iE ], params ); const bool isForward = StdMeshers_PrismAsBlock::IsForwardEdge( myHelper->GetMeshDS(), myParam2ColumnMaps[iE], *edgeIt, SMESH_Block::ID_Fx0z ); for ( int i = 0; i < nbSplit; ++i ) { double f = ( isForward ? params[ i ] : params[ nbSplit - i-1 ]); double l = ( isForward ? params[ i+1 ] : params[ nbSplit - i ]); TSideFace* comp = new TSideFace( myHelper, wallFaceIds[ iSide ], *faceIt, *edgeIt, &myParam2ColumnMaps[ iE ], f, l ); mySide->SetComponent( iSide++, comp ); } } else { TSideFace* comp = new TSideFace( myHelper, wallFaceIds[ iSide ], *faceIt, *edgeIt, &myParam2ColumnMaps[ iE ]); mySide->SetComponent( iSide++, comp ); } ++iE; } } else { // **************************** Unite faces // unite first faces int nbExraFaces = nbEdges - 3; int iSide = 0, iE; double u0 = 0, sumLen = 0; for ( iE = 0; iE < nbExraFaces; ++iE ) sumLen += edgeLength[ iE ]; vector< TSideFace* > components( nbExraFaces ); vector< pair< double, double> > params( nbExraFaces ); faceIt = wallFaces.begin(); edgeIt = orderedEdges.begin(); for ( iE = 0; iE < nbExraFaces; ++edgeIt, ++faceIt ) { components[ iE ] = new TSideFace( myHelper, wallFaceIds[ iSide ], *faceIt, *edgeIt, &myParam2ColumnMaps[ iE ]); double u1 = u0 + edgeLength[ iE ] / sumLen; params[ iE ] = make_pair( u0 , u1 ); u0 = u1; ++iE; } mySide->SetComponent( iSide++, new TSideFace( components, params )); // fill the rest faces for ( ; iE < nbEdges; ++faceIt, ++edgeIt ) { TSideFace* comp = new TSideFace( myHelper, wallFaceIds[ iSide ], *faceIt, *edgeIt, &myParam2ColumnMaps[ iE ]); mySide->SetComponent( iSide++, comp ); ++iE; } } // Fill geometry fields of SMESH_Block // ------------------------------------ TopoDS_Face botF = TopoDS::Face( botSM->GetSubShape() ); TopoDS_Face topF = TopoDS::Face( topSM->GetSubShape() ); vector< int > botEdgeIdVec; SMESH_Block::GetFaceEdgesIDs( ID_BOT_FACE, botEdgeIdVec ); bool isForward[NB_WALL_FACES] = { true, true, true, true }; Adaptor2d_Curve2d* botPcurves[NB_WALL_FACES]; Adaptor2d_Curve2d* topPcurves[NB_WALL_FACES]; for ( int iF = 0; iF < NB_WALL_FACES; ++iF ) { TSideFace * sideFace = mySide->GetComponent( iF ); if ( !sideFace ) RETURN_BAD_RESULT("NULL TSideFace"); int fID = sideFace->FaceID(); // fill myShapeIDMap if ( sideFace->InsertSubShapes( myShapeIDMap ) != 8 && !sideFace->IsComplex()) MESSAGE( ": Warning : InsertSubShapes() < 8 on side " << iF ); // side faces geometry Adaptor2d_Curve2d* pcurves[NB_WALL_FACES]; if ( !sideFace->GetPCurves( pcurves )) RETURN_BAD_RESULT("TSideFace::GetPCurves() failed"); SMESH_Block::TFace& tFace = myFace[ fID - ID_FirstF ]; tFace.Set( fID, sideFace->Surface(), pcurves, isForward ); SHOWYXZ( endl<<"F "<< iF << " id " << fID << " FRW " << sideFace->IsForward(), sideFace->Value(0,0)); // edges 3D geometry vector< int > edgeIdVec; SMESH_Block::GetFaceEdgesIDs( fID, edgeIdVec ); for ( int isMax = 0; isMax < 2; ++isMax ) { { int eID = edgeIdVec[ isMax ]; SMESH_Block::TEdge& tEdge = myEdge[ eID - ID_FirstE ]; tEdge.Set( eID, sideFace->HorizCurve(isMax), true); SHOWYXZ(eID<<" HOR"<HorizCurve(isMax)->Value(0)); SHOWYXZ(eID<<" HOR"<HorizCurve(isMax)->Value(1)); } { int eID = edgeIdVec[ isMax+2 ]; SMESH_Block::TEdge& tEdge = myEdge[ eID - ID_FirstE ]; tEdge.Set( eID, sideFace->VertiCurve(isMax), true); SHOWYXZ(eID<<" VER"<VertiCurve(isMax)->Value(0)); SHOWYXZ(eID<<" VER"<VertiCurve(isMax)->Value(1)); // corner points vector< int > vertexIdVec; SMESH_Block::GetEdgeVertexIDs( eID, vertexIdVec ); myPnt[ vertexIdVec[0] - ID_FirstV ] = tEdge.GetCurve()->Value(0).XYZ(); myPnt[ vertexIdVec[1] - ID_FirstV ] = tEdge.GetCurve()->Value(1).XYZ(); } } // pcurves on horizontal faces for ( iE = 0; iE < NB_WALL_FACES; ++iE ) { if ( edgeIdVec[ BOTTOM_EDGE ] == botEdgeIdVec[ iE ] ) { botPcurves[ iE ] = sideFace->HorizPCurve( false, botF ); topPcurves[ iE ] = sideFace->HorizPCurve( true, topF ); break; } } //sideFace->dumpNodes( 4 ); // debug } // horizontal faces geometry { SMESH_Block::TFace& tFace = myFace[ ID_BOT_FACE - ID_FirstF ]; tFace.Set( ID_BOT_FACE, new BRepAdaptor_Surface( botF ), botPcurves, isForward ); SMESH_Block::Insert( botF, ID_BOT_FACE, myShapeIDMap ); } { SMESH_Block::TFace& tFace = myFace[ ID_TOP_FACE - ID_FirstF ]; tFace.Set( ID_TOP_FACE, new BRepAdaptor_Surface( topF ), topPcurves, isForward ); SMESH_Block::Insert( topF, ID_TOP_FACE, myShapeIDMap ); } // Fill map ShapeIndex to TParam2ColumnMap // ---------------------------------------- list< TSideFace* > fList; list< TSideFace* >::iterator fListIt; fList.push_back( mySide ); for ( fListIt = fList.begin(); fListIt != fList.end(); ++fListIt) { int nb = (*fListIt)->NbComponents(); for ( int i = 0; i < nb; ++i ) { if ( TSideFace* comp = (*fListIt)->GetComponent( i )) fList.push_back( comp ); } if ( TParam2ColumnMap* cols = (*fListIt)->GetColumns()) { // columns for a base edge int id = MeshDS()->ShapeToIndex( (*fListIt)->BaseEdge() ); bool isForward = (*fListIt)->IsForward(); myShapeIndex2ColumnMap[ id ] = make_pair( cols, isForward ); // columns for vertices const SMDS_MeshNode* n0 = cols->begin()->second.front(); id = n0->getshapeId(); myShapeIndex2ColumnMap[ id ] = make_pair( cols, isForward ); const SMDS_MeshNode* n1 = cols->rbegin()->second.front(); id = n1->getshapeId(); myShapeIndex2ColumnMap[ id ] = make_pair( cols, !isForward ); } } // gp_XYZ testPar(0.25, 0.25, 0), testCoord; // if ( !FacePoint( ID_BOT_FACE, testPar, testCoord )) // RETURN_BAD_RESULT("TEST FacePoint() FAILED"); // SHOWYXZ("IN TEST PARAM" , testPar); // SHOWYXZ("OUT TEST CORD" , testCoord); // if ( !ComputeParameters( testCoord, testPar , ID_BOT_FACE)) // RETURN_BAD_RESULT("TEST ComputeParameters() FAILED"); // SHOWYXZ("OUT TEST PARAM" , testPar); return true; } //================================================================================ /*! * \brief Return pointer to column of nodes * \param node - bottom node from which the returned column goes up * \retval const TNodeColumn* - the found column */ //================================================================================ const TNodeColumn* StdMeshers_PrismAsBlock::GetNodeColumn(const SMDS_MeshNode* node) const { int sID = node->getshapeId(); map >::const_iterator col_frw = myShapeIndex2ColumnMap.find( sID ); if ( col_frw != myShapeIndex2ColumnMap.end() ) { const TParam2ColumnMap* cols = col_frw->second.first; TParam2ColumnIt u_col = cols->begin(); for ( ; u_col != cols->end(); ++u_col ) if ( u_col->second[ 0 ] == node ) return & u_col->second; } return 0; } //======================================================================= //function : GetLayersTransformation //purpose : Return transformations to get coordinates of nodes of each layer // by nodes of the bottom. Layer is a set of nodes at a certain step // from bottom to top. //======================================================================= bool StdMeshers_PrismAsBlock::GetLayersTransformation(vector & trsf) const { const int zSize = VerticalSize(); if ( zSize < 3 ) return true; trsf.resize( zSize - 2 ); // Select some node columns by which we will define coordinate system of layers vector< const TNodeColumn* > columns; { const TopoDS_Shape& baseFace = Shape(ID_BOT_FACE); list< TopoDS_Edge > orderedEdges; list< int > nbEdgesInWires; GetOrderedEdges( TopoDS::Face( baseFace ), TopoDS_Vertex(), orderedEdges, nbEdgesInWires ); bool isReverse; list< TopoDS_Edge >::iterator edgeIt = orderedEdges.begin(); for ( int iE = 0; iE < nbEdgesInWires.front(); ++iE, ++edgeIt ) { if ( BRep_Tool::Degenerated( *edgeIt )) continue; const TParam2ColumnMap* u2colMap = GetParam2ColumnMap( myHelper->GetMeshDS()->ShapeToIndex( *edgeIt ), isReverse ); if ( !u2colMap ) return false; isReverse = ( edgeIt->Orientation() == TopAbs_REVERSED ); double f = u2colMap->begin()->first, l = u2colMap->rbegin()->first; if ( isReverse ) swap ( f, l ); const int nbCol = 5; for ( int i = 0; i < nbCol; ++i ) { double u = f + i/double(nbCol) * ( l - f ); const TNodeColumn* col = & getColumn( u2colMap, u )->second; if ( columns.empty() || col != columns.back() ) columns.push_back( col ); } } } // Find tolerance to check transformations double tol2; { Bnd_B3d bndBox; for ( int i = 0; i < columns.size(); ++i ) bndBox.Add( gpXYZ( columns[i]->front() )); tol2 = bndBox.SquareExtent() * 1e-5; } // Compute transformations int xCol = -1; gp_Trsf fromCsZ, toCs0; gp_Ax3 cs0 = getLayerCoordSys(0, columns, xCol ); //double dist0 = cs0.Location().Distance( gpXYZ( (*columns[0])[0])); toCs0.SetTransformation( cs0 ); for ( int z = 1; z < zSize-1; ++z ) { gp_Ax3 csZ = getLayerCoordSys(z, columns, xCol ); //double distZ = csZ.Location().Distance( gpXYZ( (*columns[0])[z])); fromCsZ.SetTransformation( csZ ); fromCsZ.Invert(); gp_Trsf& t = trsf[ z-1 ]; t = fromCsZ * toCs0; //t.SetScaleFactor( distZ/dist0 ); - it does not work properly, wrong base point // check a transformation for ( int i = 0; i < columns.size(); ++i ) { gp_Pnt p0 = gpXYZ( (*columns[i])[0] ); gp_Pnt pz = gpXYZ( (*columns[i])[z] ); t.Transforms( p0.ChangeCoord() ); if ( p0.SquareDistance( pz ) > tol2 ) return false; } } return true; } //================================================================================ /*! * \brief Check curve orientation of a bootom edge * \param meshDS - mesh DS * \param columnsMap - node columns map of side face * \param bottomEdge - the bootom edge * \param sideFaceID - side face in-block ID * \retval bool - true if orientation coinside with in-block forward orientation */ //================================================================================ bool StdMeshers_PrismAsBlock::IsForwardEdge(SMESHDS_Mesh* meshDS, const TParam2ColumnMap& columnsMap, const TopoDS_Edge & bottomEdge, const int sideFaceID) { bool isForward = false; if ( SMESH_MesherHelper::IsClosedEdge( bottomEdge )) { isForward = ( bottomEdge.Orientation() == TopAbs_FORWARD ); } else { const TNodeColumn& firstCol = columnsMap.begin()->second; const SMDS_MeshNode* bottomNode = firstCol[0]; TopoDS_Shape firstVertex = SMESH_MesherHelper::GetSubShapeByNode( bottomNode, meshDS ); isForward = ( firstVertex.IsSame( TopExp::FirstVertex( bottomEdge, true ))); } // on 2 of 4 sides first vertex is end if ( sideFaceID == ID_Fx1z || sideFaceID == ID_F0yz ) isForward = !isForward; return isForward; } //================================================================================ /*! * \brief Find wall faces by bottom edges * \param mesh - the mesh * \param mainShape - the prism * \param bottomFace - the bottom face * \param bottomEdges - edges bounding the bottom face * \param wallFaces - faces list to fill in */ //================================================================================ bool StdMeshers_PrismAsBlock::GetWallFaces( SMESH_Mesh* mesh, const TopoDS_Shape & mainShape, const TopoDS_Shape & bottomFace, std::list< TopoDS_Edge >& bottomEdges, std::list< int > & nbEInW, std::list< TopoDS_Face >& wallFaces) { wallFaces.clear(); TopTools_IndexedMapOfShape faceMap; TopExp::MapShapes( mainShape, TopAbs_FACE, faceMap ); list< TopoDS_Edge >::iterator edge = bottomEdges.begin(); std::list< int >::iterator nbE = nbEInW.begin(); int iE = 0; while ( edge != bottomEdges.end() ) { ++iE; if ( BRep_Tool::Degenerated( *edge )) { edge = bottomEdges.erase( edge ); --iE; --(*nbE); } else { PShapeIteratorPtr fIt = myHelper->GetAncestors( *edge, *mesh, TopAbs_FACE ); while ( fIt->more() ) { const TopoDS_Shape* face = fIt->next(); if ( !bottomFace.IsSame( *face ) && // not bottom faceMap.FindIndex( *face )) // belongs to the prism { wallFaces.push_back( TopoDS::Face( *face )); break; } } ++edge; } if ( iE == *nbE ) { iE = 0; ++nbE; } } return ( wallFaces.size() == bottomEdges.size() ); } //================================================================================ /*! * \brief Constructor * \param faceID - in-block ID * \param face - geom face * \param columnsMap - map of node columns * \param first - first normalized param * \param last - last normalized param */ //================================================================================ StdMeshers_PrismAsBlock::TSideFace::TSideFace(SMESH_MesherHelper* helper, const int faceID, const TopoDS_Face& face, const TopoDS_Edge& baseEdge, TParam2ColumnMap* columnsMap, const double first, const double last): myID( faceID ), myParamToColumnMap( columnsMap ), myBaseEdge( baseEdge ), myHelper( helper ) { mySurface.Initialize( face ); myParams.resize( 1 ); myParams[ 0 ] = make_pair( first, last ); myIsForward = StdMeshers_PrismAsBlock::IsForwardEdge( myHelper->GetMeshDS(), *myParamToColumnMap, myBaseEdge, myID ); } //================================================================================ /*! * \brief Constructor of complex side face */ //================================================================================ StdMeshers_PrismAsBlock::TSideFace:: TSideFace(const vector< TSideFace* >& components, const vector< pair< double, double> > & params) :myID( components[0] ? components[0]->myID : 0 ), myParamToColumnMap( 0 ), myParams( params ), myIsForward( true ), myComponents( components ), myHelper( components[0] ? components[0]->myHelper : 0 ) {} //================================================================================ /*! * \brief Copy constructor * \param other - other side */ //================================================================================ StdMeshers_PrismAsBlock::TSideFace::TSideFace( const TSideFace& other ) { myID = other.myID; mySurface = other.mySurface; myBaseEdge = other.myBaseEdge; myParams = other.myParams; myIsForward = other.myIsForward; myHelper = other.myHelper; myParamToColumnMap = other.myParamToColumnMap; myComponents.resize( other.myComponents.size()); for (int i = 0 ; i < myComponents.size(); ++i ) myComponents[ i ] = new TSideFace( *other.myComponents[ i ]); } //================================================================================ /*! * \brief Deletes myComponents */ //================================================================================ StdMeshers_PrismAsBlock::TSideFace::~TSideFace() { for (int i = 0 ; i < myComponents.size(); ++i ) if ( myComponents[ i ] ) delete myComponents[ i ]; } //================================================================================ /*! * \brief Return geometry of the vertical curve * \param isMax - true means curve located closer to (1,1,1) block point * \retval Adaptor3d_Curve* - curve adaptor */ //================================================================================ Adaptor3d_Curve* StdMeshers_PrismAsBlock::TSideFace::VertiCurve(const bool isMax) const { if ( !myComponents.empty() ) { if ( isMax ) return myComponents.back()->VertiCurve(isMax); else return myComponents.front()->VertiCurve(isMax); } double f = myParams[0].first, l = myParams[0].second; if ( !myIsForward ) std::swap( f, l ); return new TVerticalEdgeAdaptor( myParamToColumnMap, isMax ? l : f ); } //================================================================================ /*! * \brief Return geometry of the top or bottom curve * \param isTop - * \retval Adaptor3d_Curve* - */ //================================================================================ Adaptor3d_Curve* StdMeshers_PrismAsBlock::TSideFace::HorizCurve(const bool isTop) const { return new THorizontalEdgeAdaptor( this, isTop ); } //================================================================================ /*! * \brief Return pcurves * \param pcurv - array of 4 pcurves * \retval bool - is a success */ //================================================================================ bool StdMeshers_PrismAsBlock::TSideFace::GetPCurves(Adaptor2d_Curve2d* pcurv[4]) const { int iEdge[ 4 ] = { BOTTOM_EDGE, TOP_EDGE, V0_EDGE, V1_EDGE }; for ( int i = 0 ; i < 4 ; ++i ) { Handle(Geom2d_Line) line; switch ( iEdge[ i ] ) { case TOP_EDGE: line = new Geom2d_Line( gp_Pnt2d( 0, 1 ), gp::DX2d() ); break; case BOTTOM_EDGE: line = new Geom2d_Line( gp::Origin2d(), gp::DX2d() ); break; case V0_EDGE: line = new Geom2d_Line( gp::Origin2d(), gp::DY2d() ); break; case V1_EDGE: line = new Geom2d_Line( gp_Pnt2d( 1, 0 ), gp::DY2d() ); break; } pcurv[ i ] = new Geom2dAdaptor_Curve( line, 0, 1 ); } return true; } //================================================================================ /*! * \brief Returns geometry of pcurve on a horizontal face * \param isTop - is top or bottom face * \param horFace - a horizontal face * \retval Adaptor2d_Curve2d* - curve adaptor */ //================================================================================ Adaptor2d_Curve2d* StdMeshers_PrismAsBlock::TSideFace::HorizPCurve(const bool isTop, const TopoDS_Face& horFace) const { return new TPCurveOnHorFaceAdaptor( this, isTop, horFace ); } //================================================================================ /*! * \brief Return a component corresponding to parameter * \param U - parameter along a horizontal size * \param localU - parameter along a horizontal size of a component * \retval TSideFace* - found component */ //================================================================================ StdMeshers_PrismAsBlock::TSideFace* StdMeshers_PrismAsBlock::TSideFace::GetComponent(const double U,double & localU) const { localU = U; if ( myComponents.empty() ) return const_cast( this ); int i; for ( i = 0; i < myComponents.size(); ++i ) if ( U < myParams[ i ].second ) break; if ( i >= myComponents.size() ) i = myComponents.size() - 1; double f = myParams[ i ].first, l = myParams[ i ].second; localU = ( U - f ) / ( l - f ); return myComponents[ i ]; } //================================================================================ /*! * \brief Find node columns for a parameter * \param U - parameter along a horizontal edge * \param col1 - the 1st found column * \param col2 - the 2nd found column * \retval r - normalized position of U between the found columns */ //================================================================================ double StdMeshers_PrismAsBlock::TSideFace::GetColumns(const double U, TParam2ColumnIt & col1, TParam2ColumnIt & col2) const { double u = U, r = 0; if ( !myComponents.empty() ) { TSideFace * comp = GetComponent(U,u); return comp->GetColumns( u, col1, col2 ); } if ( !myIsForward ) u = 1 - u; double f = myParams[0].first, l = myParams[0].second; u = f + u * ( l - f ); col1 = col2 = getColumn( myParamToColumnMap, u ); if ( ++col2 == myParamToColumnMap->end() ) { --col2; r = 0.5; } else { double uf = col1->first; double ul = col2->first; r = ( u - uf ) / ( ul - uf ); } return r; } //================================================================================ /*! * \brief Return coordinates by normalized params * \param U - horizontal param * \param V - vertical param * \retval gp_Pnt - result point */ //================================================================================ gp_Pnt StdMeshers_PrismAsBlock::TSideFace::Value(const Standard_Real U, const Standard_Real V) const { if ( !myComponents.empty() ) { double u; TSideFace * comp = GetComponent(U,u); return comp->Value( u, V ); } TParam2ColumnIt u_col1, u_col2; double vR, hR = GetColumns( U, u_col1, u_col2 ); const SMDS_MeshNode* n1 = 0; const SMDS_MeshNode* n2 = 0; const SMDS_MeshNode* n3 = 0; const SMDS_MeshNode* n4 = 0; // BEGIN issue 0020680: EDF 1252 SMESH: Bad cell created by Radial prism in center of torus // Workaround for a wrongly located point returned by mySurface.Value() for // UV located near boundary of BSpline surface. // To bypass the problem, we take point from 3D curve of edge. // It solves pb of the bloc_fiss_new.py const double tol = 1e-3; if ( V < tol || V+tol >= 1. ) { n1 = V < tol ? u_col1->second.front() : u_col1->second.back(); n3 = V < tol ? u_col2->second.front() : u_col2->second.back(); TopoDS_Edge edge; if ( V < tol ) { edge = myBaseEdge; } else { TopoDS_Shape s = myHelper->GetSubShapeByNode( n1, myHelper->GetMeshDS() ); if ( s.ShapeType() != TopAbs_EDGE ) s = myHelper->GetSubShapeByNode( n3, myHelper->GetMeshDS() ); if ( s.ShapeType() == TopAbs_EDGE ) edge = TopoDS::Edge( s ); } if ( !edge.IsNull() ) { double u1 = myHelper->GetNodeU( edge, n1 ); double u3 = myHelper->GetNodeU( edge, n3 ); double u = u1 * ( 1 - hR ) + u3 * hR; TopLoc_Location loc; double f,l; Handle(Geom_Curve) curve = BRep_Tool::Curve( edge,loc,f,l ); return curve->Value( u ).Transformed( loc ); } } // END issue 0020680: EDF 1252 SMESH: Bad cell created by Radial prism in center of torus vR = getRAndNodes( & u_col1->second, V, n1, n2 ); vR = getRAndNodes( & u_col2->second, V, n3, n4 ); gp_XY uv1 = myHelper->GetNodeUV( mySurface.Face(), n1, n4); gp_XY uv2 = myHelper->GetNodeUV( mySurface.Face(), n2, n3); gp_XY uv12 = uv1 * ( 1 - vR ) + uv2 * vR; gp_XY uv3 = myHelper->GetNodeUV( mySurface.Face(), n3, n2); gp_XY uv4 = myHelper->GetNodeUV( mySurface.Face(), n4, n1); gp_XY uv34 = uv3 * ( 1 - vR ) + uv4 * vR; gp_XY uv = uv12 * ( 1 - hR ) + uv34 * hR; gp_Pnt p = mySurface.Value( uv.X(), uv.Y() ); return p; } //================================================================================ /*! * \brief Return boundary edge * \param edge - edge index * \retval TopoDS_Edge - found edge */ //================================================================================ TopoDS_Edge StdMeshers_PrismAsBlock::TSideFace::GetEdge(const int iEdge) const { if ( !myComponents.empty() ) { switch ( iEdge ) { case V0_EDGE : return myComponents.front()->GetEdge( iEdge ); case V1_EDGE : return myComponents.back() ->GetEdge( iEdge ); default: return TopoDS_Edge(); } } TopoDS_Shape edge; const SMDS_MeshNode* node = 0; SMESHDS_Mesh * meshDS = myHelper->GetMesh()->GetMeshDS(); TNodeColumn* column; switch ( iEdge ) { case TOP_EDGE: case BOTTOM_EDGE: column = & (( ++myParamToColumnMap->begin())->second ); node = ( iEdge == TOP_EDGE ) ? column->back() : column->front(); edge = myHelper->GetSubShapeByNode ( node, meshDS ); if ( edge.ShapeType() == TopAbs_VERTEX ) { column = & ( myParamToColumnMap->begin()->second ); node = ( iEdge == TOP_EDGE ) ? column->back() : column->front(); } break; case V0_EDGE: case V1_EDGE: { bool back = ( iEdge == V1_EDGE ); if ( !myIsForward ) back = !back; if ( back ) column = & ( myParamToColumnMap->rbegin()->second ); else column = & ( myParamToColumnMap->begin()->second ); if ( column->size() > 0 ) edge = myHelper->GetSubShapeByNode( (*column)[ 1 ], meshDS ); if ( edge.IsNull() || edge.ShapeType() == TopAbs_VERTEX ) node = column->front(); break; } default:; } if ( !edge.IsNull() && edge.ShapeType() == TopAbs_EDGE ) return TopoDS::Edge( edge ); // find edge by 2 vertices TopoDS_Shape V1 = edge; TopoDS_Shape V2 = myHelper->GetSubShapeByNode( node, meshDS ); if ( !V2.IsNull() && V2.ShapeType() == TopAbs_VERTEX && !V2.IsSame( V1 )) { TopoDS_Shape ancestor = myHelper->GetCommonAncestor( V1, V2, *myHelper->GetMesh(), TopAbs_EDGE); if ( !ancestor.IsNull() ) return TopoDS::Edge( ancestor ); } return TopoDS_Edge(); } //================================================================================ /*! * \brief Fill block sub-shapes * \param shapeMap - map to fill in * \retval int - nb inserted sub-shapes */ //================================================================================ int StdMeshers_PrismAsBlock::TSideFace::InsertSubShapes(TBlockShapes& shapeMap) const { int nbInserted = 0; // Insert edges vector< int > edgeIdVec; SMESH_Block::GetFaceEdgesIDs( myID, edgeIdVec ); for ( int i = BOTTOM_EDGE; i <=V1_EDGE ; ++i ) { TopoDS_Edge e = GetEdge( i ); if ( !e.IsNull() ) { nbInserted += SMESH_Block::Insert( e, edgeIdVec[ i ], shapeMap); } } // Insert corner vertices TParam2ColumnIt col1, col2 ; vector< int > vertIdVec; // from V0 column SMESH_Block::GetEdgeVertexIDs( edgeIdVec[ V0_EDGE ], vertIdVec); GetColumns(0, col1, col2 ); const SMDS_MeshNode* node0 = col1->second.front(); const SMDS_MeshNode* node1 = col1->second.back(); TopoDS_Shape v0 = myHelper->GetSubShapeByNode( node0, myHelper->GetMeshDS()); TopoDS_Shape v1 = myHelper->GetSubShapeByNode( node1, myHelper->GetMeshDS()); if ( v0.ShapeType() == TopAbs_VERTEX ) { nbInserted += SMESH_Block::Insert( v0, vertIdVec[ 0 ], shapeMap); } if ( v1.ShapeType() == TopAbs_VERTEX ) { nbInserted += SMESH_Block::Insert( v1, vertIdVec[ 1 ], shapeMap); } // from V1 column SMESH_Block::GetEdgeVertexIDs( edgeIdVec[ V1_EDGE ], vertIdVec); GetColumns(1, col1, col2 ); node0 = col2->second.front(); node1 = col2->second.back(); v0 = myHelper->GetSubShapeByNode( node0, myHelper->GetMeshDS()); v1 = myHelper->GetSubShapeByNode( node1, myHelper->GetMeshDS()); if ( v0.ShapeType() == TopAbs_VERTEX ) { nbInserted += SMESH_Block::Insert( v0, vertIdVec[ 0 ], shapeMap); } if ( v1.ShapeType() == TopAbs_VERTEX ) { nbInserted += SMESH_Block::Insert( v1, vertIdVec[ 1 ], shapeMap); } // TopoDS_Vertex V0, V1, Vcom; // TopExp::Vertices( myBaseEdge, V0, V1, true ); // if ( !myIsForward ) std::swap( V0, V1 ); // // bottom vertex IDs // SMESH_Block::GetEdgeVertexIDs( edgeIdVec[ _u0 ], vertIdVec); // SMESH_Block::Insert( V0, vertIdVec[ 0 ], shapeMap); // SMESH_Block::Insert( V1, vertIdVec[ 1 ], shapeMap); // TopoDS_Edge sideEdge = GetEdge( V0_EDGE ); // if ( sideEdge.IsNull() || !TopExp::CommonVertex( botEdge, sideEdge, Vcom )) // return false; // // insert one side edge // int edgeID; // if ( Vcom.IsSame( V0 )) edgeID = edgeIdVec[ _v0 ]; // else edgeID = edgeIdVec[ _v1 ]; // SMESH_Block::Insert( sideEdge, edgeID, shapeMap); // // top vertex of the side edge // SMESH_Block::GetEdgeVertexIDs( edgeID, vertIdVec); // TopoDS_Vertex Vtop = TopExp::FirstVertex( sideEdge ); // if ( Vcom.IsSame( Vtop )) // Vtop = TopExp::LastVertex( sideEdge ); // SMESH_Block::Insert( Vtop, vertIdVec[ 1 ], shapeMap); // // other side edge // sideEdge = GetEdge( V1_EDGE ); // if ( sideEdge.IsNull() ) // return false; // if ( edgeID = edgeIdVec[ _v1 ]) edgeID = edgeIdVec[ _v0 ]; // else edgeID = edgeIdVec[ _v1 ]; // SMESH_Block::Insert( sideEdge, edgeID, shapeMap); // // top edge // TopoDS_Edge topEdge = GetEdge( TOP_EDGE ); // SMESH_Block::Insert( topEdge, edgeIdVec[ _u1 ], shapeMap); // // top vertex of the other side edge // if ( !TopExp::CommonVertex( topEdge, sideEdge, Vcom )) // return false; // SMESH_Block::GetEdgeVertexIDs( edgeID, vertIdVec ); // SMESH_Block::Insert( Vcom, vertIdVec[ 1 ], shapeMap); return nbInserted; } //================================================================================ /*! * \brief Dump ids of nodes of sides */ //================================================================================ void StdMeshers_PrismAsBlock::TSideFace::dumpNodes(int nbNodes) const { #ifdef _DEBUG_ cout << endl << "NODES OF FACE "; SMESH_Block::DumpShapeID( myID, cout ) << endl; THorizontalEdgeAdaptor* hSize0 = (THorizontalEdgeAdaptor*) HorizCurve(0); cout << "Horiz side 0: "; hSize0->dumpNodes(nbNodes); cout << endl; THorizontalEdgeAdaptor* hSize1 = (THorizontalEdgeAdaptor*) HorizCurve(1); cout << "Horiz side 1: "; hSize1->dumpNodes(nbNodes); cout << endl; TVerticalEdgeAdaptor* vSide0 = (TVerticalEdgeAdaptor*) VertiCurve(0); cout << "Verti side 0: "; vSide0->dumpNodes(nbNodes); cout << endl; TVerticalEdgeAdaptor* vSide1 = (TVerticalEdgeAdaptor*) VertiCurve(1); cout << "Verti side 1: "; vSide1->dumpNodes(nbNodes); cout << endl; delete hSize0; delete hSize1; delete vSide0; delete vSide1; #endif } //================================================================================ /*! * \brief Creates TVerticalEdgeAdaptor * \param columnsMap - node column map * \param parameter - normalized parameter */ //================================================================================ StdMeshers_PrismAsBlock::TVerticalEdgeAdaptor:: TVerticalEdgeAdaptor( const TParam2ColumnMap* columnsMap, const double parameter) { myNodeColumn = & getColumn( columnsMap, parameter )->second; } //================================================================================ /*! * \brief Return coordinates for the given normalized parameter * \param U - normalized parameter * \retval gp_Pnt - coordinates */ //================================================================================ gp_Pnt StdMeshers_PrismAsBlock::TVerticalEdgeAdaptor::Value(const Standard_Real U) const { const SMDS_MeshNode* n1; const SMDS_MeshNode* n2; double r = getRAndNodes( myNodeColumn, U, n1, n2 ); return gpXYZ(n1) * ( 1 - r ) + gpXYZ(n2) * r; } //================================================================================ /*! * \brief Dump ids of nodes */ //================================================================================ void StdMeshers_PrismAsBlock::TVerticalEdgeAdaptor::dumpNodes(int nbNodes) const { #ifdef _DEBUG_ for ( int i = 0; i < nbNodes && i < myNodeColumn->size(); ++i ) cout << (*myNodeColumn)[i]->GetID() << " "; if ( nbNodes < myNodeColumn->size() ) cout << myNodeColumn->back()->GetID(); #endif } //================================================================================ /*! * \brief Return coordinates for the given normalized parameter * \param U - normalized parameter * \retval gp_Pnt - coordinates */ //================================================================================ gp_Pnt StdMeshers_PrismAsBlock::THorizontalEdgeAdaptor::Value(const Standard_Real U) const { return mySide->TSideFace::Value( U, myV ); } //================================================================================ /*! * \brief Dump ids of first nodes and the last one */ //================================================================================ void StdMeshers_PrismAsBlock::THorizontalEdgeAdaptor::dumpNodes(int nbNodes) const { #ifdef _DEBUG_ // Not bedugged code. Last node is sometimes incorrect const TSideFace* side = mySide; double u = 0; if ( mySide->IsComplex() ) side = mySide->GetComponent(0,u); TParam2ColumnIt col, col2; TParam2ColumnMap* u2cols = side->GetColumns(); side->GetColumns( u , col, col2 ); int j, i = myV ? mySide->ColumnHeight()-1 : 0; const SMDS_MeshNode* n = 0; const SMDS_MeshNode* lastN = side->IsForward() ? u2cols->rbegin()->second[ i ] : u2cols->begin()->second[ i ]; for ( j = 0; j < nbNodes && n != lastN; ++j ) { n = col->second[ i ]; cout << n->GetID() << " "; if ( side->IsForward() ) ++col; else --col; } // last node u = 1; if ( mySide->IsComplex() ) side = mySide->GetComponent(1,u); side->GetColumns( u , col, col2 ); if ( n != col->second[ i ] ) cout << col->second[ i ]->GetID(); #endif } //================================================================================ /*! * \brief Return UV on pcurve for the given normalized parameter * \param U - normalized parameter * \retval gp_Pnt - coordinates */ //================================================================================ gp_Pnt2d StdMeshers_PrismAsBlock::TPCurveOnHorFaceAdaptor::Value(const Standard_Real U) const { TParam2ColumnIt u_col1, u_col2; double r = mySide->GetColumns( U, u_col1, u_col2 ); gp_XY uv1 = mySide->GetNodeUV( myFace, u_col1->second[ myZ ]); gp_XY uv2 = mySide->GetNodeUV( myFace, u_col2->second[ myZ ]); return uv1 * ( 1 - r ) + uv2 * r; }