X-Git-Url: http://git.salome-platform.org/gitweb/?p=modules%2Fsmesh.git;a=blobdiff_plain;f=src%2FStdMeshers%2FStdMeshers_Quadrangle_2D.cxx;h=0a7e3301754ee315929c1e865e4f646dca1dfd59;hp=e24cc375c85fdd1394fc0b583116eb6322b301bb;hb=f90e1ea49e27e4188ba8bff184ec45f28fd3574a;hpb=e12cb3f8c3219fb5d53a7a23569011f1009ffd41 diff --git a/src/StdMeshers/StdMeshers_Quadrangle_2D.cxx b/src/StdMeshers/StdMeshers_Quadrangle_2D.cxx index e24cc375c..0a7e33017 100644 --- a/src/StdMeshers/StdMeshers_Quadrangle_2D.cxx +++ b/src/StdMeshers/StdMeshers_Quadrangle_2D.cxx @@ -1,4 +1,4 @@ -// Copyright (C) 2007-2013 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2014 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 @@ -6,7 +6,7 @@ // 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. +// 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 @@ -42,8 +42,10 @@ #include "StdMeshers_QuadrangleParams.hxx" #include "StdMeshers_ViscousLayers2D.hxx" +#include #include #include +#include #include #include #include @@ -88,6 +90,7 @@ StdMeshers_Quadrangle_2D::StdMeshers_Quadrangle_2D (int hypId, int studyId, myTrianglePreference(false), myTriaVertexID(-1), myNeedSmooth(false), + myCheckOri(false), myParams( NULL ), myQuadType(QUAD_STANDARD), myHelper( NULL ) @@ -213,15 +216,20 @@ bool StdMeshers_Quadrangle_2D::Compute (SMESH_Mesh& aMesh, const TopoDS_Face& F = TopoDS::Face(aShape); aMesh.GetSubMesh( F ); + // do not initialize my fields before this as StdMeshers_ViscousLayers2D + // can call Compute() recursively + SMESH_ProxyMesh::Ptr proxyMesh = StdMeshers_ViscousLayers2D::Compute( aMesh, F ); + if ( !proxyMesh ) + return false; + + myProxyMesh = proxyMesh; + SMESH_MesherHelper helper (aMesh); myHelper = &helper; - myProxyMesh = StdMeshers_ViscousLayers2D::Compute( aMesh, F ); - if ( !myProxyMesh ) - return false; - _quadraticMesh = myHelper->IsQuadraticSubMesh(aShape); myNeedSmooth = false; + myCheckOri = false; FaceQuadStruct::Ptr quad = CheckNbEdges( aMesh, F, /*considerMesh=*/true ); if (!quad) @@ -288,6 +296,9 @@ bool StdMeshers_Quadrangle_2D::Compute (SMESH_Mesh& aMesh, if ( res == COMPUTE_OK && myNeedSmooth ) smooth( quad ); + if ( res == COMPUTE_OK ) + res = check(); + return ( res == COMPUTE_OK ); } @@ -317,17 +328,25 @@ bool StdMeshers_Quadrangle_2D::computeTriangles(SMESH_Mesh& aMesh, if ( !setNormalizedGrid( quad )) return false; - if ( quad->nbNodeOut( QUAD_BOTTOM_SIDE )) - { - splitQuad( quad, 0, 1 ); - } if ( quad->nbNodeOut( QUAD_TOP_SIDE )) { splitQuad( quad, 0, quad->jSize-2 ); } + if ( quad->nbNodeOut( QUAD_BOTTOM_SIDE )) // this should not happen + { + splitQuad( quad, 0, 1 ); + } FaceQuadStruct::Ptr newQuad = myQuadList.back(); if ( quad != newQuad ) // split done { + { + FaceQuadStruct::Ptr botQuad = // a bottom part + ( quad->side[ QUAD_LEFT_SIDE ].from == 0 ) ? quad : newQuad; + if ( botQuad->nbNodeOut( QUAD_LEFT_SIDE ) > 0 ) + botQuad->side[ QUAD_LEFT_SIDE ].to += botQuad->nbNodeOut( QUAD_LEFT_SIDE ); + else if ( botQuad->nbNodeOut( QUAD_RIGHT_SIDE ) > 0 ) + botQuad->side[ QUAD_RIGHT_SIDE ].to += botQuad->nbNodeOut( QUAD_RIGHT_SIDE ); + } // make quad be a greatest one if ( quad->side[ QUAD_LEFT_SIDE ].NbPoints() == 2 || quad->side[ QUAD_RIGHT_SIDE ].NbPoints() == 2 ) @@ -455,7 +474,7 @@ bool StdMeshers_Quadrangle_2D::computeQuadDominant(SMESH_Mesh& aMesh, int nbright = (int) uv_e1.size(); int nbleft = (int) uv_e3.size(); - if (quad->nbNodeOut(0) && nbvertic == 2) + if (quad->nbNodeOut(0) && nbvertic == 2) // this should not occure { // Down edge is out // @@ -649,7 +668,7 @@ bool StdMeshers_Quadrangle_2D::computeQuadDominant(SMESH_Mesh& aMesh, } // right or left boundary quadrangles - if (quad->nbNodeOut( QUAD_RIGHT_SIDE ) && nbhoriz == 2) + if (quad->nbNodeOut( QUAD_RIGHT_SIDE ) && nbhoriz == 2) // this should not occure { int g = 0; // last processed node in the grid int stop = nbright - 1; @@ -725,9 +744,7 @@ bool StdMeshers_Quadrangle_2D::computeQuadDominant(SMESH_Mesh& aMesh, // MESSAGE("left edge is out"); int g = nbvertic - 1; // last processed node in the grid int stop = 0; - i = nbleft - 1; - if (quad->side[3].from != stop ) stop++; - if (quad->side[3].to != i ) i--; + i = quad->side[ QUAD_LEFT_SIDE ].to-1; // nbleft - 1; for (; i > stop; i--) { const SMDS_MeshNode *a, *b, *c, *d; a = uv_e3[i].node; @@ -892,6 +909,38 @@ bool StdMeshers_Quadrangle_2D::Evaluate(SMESH_Mesh& aMesh, return true; } +//================================================================================ +/*! + * \brief Return true if the algorithm can mesh this shape + * \param [in] aShape - shape to check + * \param [in] toCheckAll - if true, this check returns OK if all shapes are OK, + * else, returns OK if at least one shape is OK + */ +//================================================================================ + +bool StdMeshers_Quadrangle_2D::IsApplicable( const TopoDS_Shape & aShape, bool toCheckAll ) +{ + int nbFoundFaces = 0; + for (TopExp_Explorer exp( aShape, TopAbs_FACE ); exp.More(); exp.Next(), ++nbFoundFaces ) + { + const TopoDS_Shape& aFace = exp.Current(); + int nbWire = SMESH_MesherHelper::Count( aFace, TopAbs_WIRE, false ); + if ( nbWire != 1 ) { + if ( toCheckAll ) return false; + continue; + } + + int nbNoDegenEdges = 0; + TopExp_Explorer eExp( aFace, TopAbs_EDGE ); + for ( ; eExp.More() && nbNoDegenEdges < 3; eExp.Next() ) { + if ( !SMESH_Algo::isDegenerated( TopoDS::Edge( eExp.Current() ))) + ++nbNoDegenEdges; + } + if ( toCheckAll && nbNoDegenEdges < 3 ) return false; + if ( !toCheckAll && nbNoDegenEdges >= 3 ) return true; + } + return ( toCheckAll && nbFoundFaces != 0 ); +} //================================================================================ /*! @@ -931,7 +980,7 @@ FaceQuadStruct::Ptr StdMeshers_Quadrangle_2D::CheckNbEdges(SMESH_Mesh & if ( F.Orientation() >= TopAbs_INTERNAL ) F.Orientation( TopAbs_FORWARD ); const bool ignoreMediumNodes = _quadraticMesh; - // verify 1 wire only, with 4 edges + // verify 1 wire only list< TopoDS_Edge > edges; list< int > nbEdgesInWire; int nbWire = SMESH_Block::GetOrderedEdges (F, edges, nbEdgesInWire); @@ -3639,6 +3688,18 @@ namespace // data for smoothing double d = v1 ^ v2; return d > 1e-100; } + //================================================================================ + /*! + * \brief Returns area of a triangle + */ + //================================================================================ + + double getArea( const gp_UV uv1, const gp_UV uv2, const gp_UV uv3 ) + { + gp_XY v1 = uv1 - uv2, v2 = uv3 - uv2; + double a = v2 ^ v1; + return a; + } } //================================================================================ @@ -3726,6 +3787,8 @@ void StdMeshers_Quadrangle_2D::smooth (FaceQuadStruct::Ptr quad) // Get nodes to smooth + // TODO: do not smooth fixed nodes + typedef map< const SMDS_MeshNode*, TSmoothNode, TIDCompare > TNo2SmooNoMap; TNo2SmooNoMap smooNoMap; @@ -3879,6 +3942,144 @@ void StdMeshers_Quadrangle_2D::smooth (FaceQuadStruct::Ptr quad) } } +//================================================================================ +/*! + * \brief Checks validity of generated faces + */ +//================================================================================ + +bool StdMeshers_Quadrangle_2D::check() +{ + const bool isOK = true; + if ( !myCheckOri || myQuadList.empty() || !myQuadList.front() || !myHelper ) + return isOK; + + TopoDS_Face geomFace = TopoDS::Face( myHelper->GetSubShape() ); + SMESHDS_Mesh* meshDS = myHelper->GetMeshDS(); + SMESHDS_SubMesh* fSubMesh = meshDS->MeshElements( geomFace ); + bool toCheckUV; + if ( geomFace.Orientation() >= TopAbs_INTERNAL ) geomFace.Orientation( TopAbs_FORWARD ); + + // Get a reference orientation sign + + double okSign; + { + TError err; + TSideVector wireVec = + StdMeshers_FaceSide::GetFaceWires( geomFace, *myHelper->GetMesh(), true, err ); + StdMeshers_FaceSidePtr wire = wireVec[0]; + + // find a right angle VERTEX + int iVertex; + double maxAngle = -1e100; + for ( int i = 0; i < wire->NbEdges(); ++i ) + { + int iPrev = myHelper->WrapIndex( i-1, wire->NbEdges() ); + const TopoDS_Edge& e1 = wire->Edge( iPrev ); + const TopoDS_Edge& e2 = wire->Edge( i ); + double angle = myHelper->GetAngle( e1, e2, geomFace ); + if ( maxAngle < angle && angle < 0.9 * M_PI ) + { + maxAngle = angle; + iVertex = i; + } + } + if ( maxAngle < -2*M_PI ) return isOK; + + // get a sign of 2D area of a corner face + + int iPrev = myHelper->WrapIndex( iVertex-1, wire->NbEdges() ); + const TopoDS_Edge& e1 = wire->Edge( iPrev ); + const TopoDS_Edge& e2 = wire->Edge( iVertex ); + + gp_Vec2d v1, v2; gp_Pnt2d p; + double u[2]; + { + bool rev = ( e1.Orientation() == TopAbs_REVERSED ); + Handle(Geom2d_Curve) c = BRep_Tool::CurveOnSurface( e1, geomFace, u[0], u[1] ); + c->D1( u[ !rev ], p, v1 ); + if ( !rev ) + v1.Reverse(); + } + { + bool rev = ( e2.Orientation() == TopAbs_REVERSED ); + Handle(Geom2d_Curve) c = BRep_Tool::CurveOnSurface( e2, geomFace, u[0], u[1] ); + c->D1( u[ rev ], p, v2 ); + if ( rev ) + v2.Reverse(); + } + + okSign = v2 ^ v1; + + if ( maxAngle < 0 ) + okSign *= -1; + } + + // Look for incorrectly oriented faces + + std::list badFaces; + + const SMDS_MeshNode* nn [ 8 ]; // 8 is just for safety + gp_UV uv [ 8 ]; + SMDS_ElemIteratorPtr fIt = fSubMesh->GetElements(); + while ( fIt->more() ) // loop on faces bound to a FACE + { + const SMDS_MeshElement* f = fIt->next(); + + const int nbN = f->NbCornerNodes(); + for ( int i = 0; i < nbN; ++i ) + nn[ i ] = f->GetNode( i ); + + const SMDS_MeshNode* nInFace = 0; + if ( myHelper->HasSeam() ) + for ( int i = 0; i < nbN && !nInFace; ++i ) + if ( !myHelper->IsSeamShape( nn[i]->getshapeId() )) + nInFace = nn[i]; + + for ( int i = 0; i < nbN; ++i ) + uv[ i ] = myHelper->GetNodeUV( geomFace, nn[i], nInFace, &toCheckUV ); + + switch ( nbN ) { + case 4: + { + double sign1 = getArea( uv[0], uv[1], uv[2] ); + double sign2 = getArea( uv[0], uv[2], uv[3] ); + if ( sign1 * sign2 < 0 ) + { + sign2 = getArea( uv[1], uv[2], uv[3] ); + sign1 = getArea( uv[1], uv[3], uv[0] ); + if ( sign1 * sign2 < 0 ) + continue; // this should not happen + } + if ( sign1 * okSign < 0 ) + badFaces.push_back ( f ); + break; + } + case 3: + { + double sign = getArea( uv[0], uv[1], uv[2] ); + if ( sign * okSign < 0 ) + badFaces.push_back ( f ); + break; + } + default:; + } + } + + if ( !badFaces.empty() ) + { + SMESH_subMesh* fSM = myHelper->GetMesh()->GetSubMesh( geomFace ); + SMESH_ComputeErrorPtr& err = fSM->GetComputeError(); + err.reset ( new SMESH_ComputeError( COMPERR_ALGO_FAILED, + "Inverted elements generated")); + err->myBadElements.swap( badFaces ); + + return !isOK; + } + + return isOK; +} + /*//================================================================================ /*! * \brief Finds vertices at the most sharp face corners @@ -3941,7 +4142,8 @@ int StdMeshers_Quadrangle_2D::getCorners(const TopoDS_Face& theFace, TopoDS_Shape triaVertex = helper.GetMeshDS()->IndexToShape( myTriaVertexID ); if ( !triaVertex.IsNull() && triaVertex.ShapeType() == TopAbs_VERTEX && - helper.IsSubShape( triaVertex, theFace )) + helper.IsSubShape( triaVertex, theFace ) && + ( vertexByAngle.size() != 4 || vertexByAngle.begin()->first < 5 * M_PI/180. )) nbCorners = 3; else triaVertex.Nullify(); @@ -3992,6 +4194,9 @@ int StdMeshers_Quadrangle_2D::getCorners(const TopoDS_Face& theFace, isThereVariants = ( lostAngle * 1.1 >= lastAngle ); } + myCheckOri = ( vertexByAngle.size() > nbCorners || + vertexByAngle.begin()->first < 5.* M_PI/180 ); + // make theWire begin from a corner vertex or triaVertex if ( nbCorners == 3 ) while ( !triaVertex.IsSame( ( helper.IthVertex( 0, theWire.front() ))) || @@ -4194,6 +4399,9 @@ bool StdMeshers_Quadrangle_2D::getEnforcedUV() surf->Bounds( u1,u2,v1,v2 ); GeomAPI_ProjectPointOnSurf project; project.Init(surf, u1,u2, v1,v2, tol ); + Bnd_Box bbox; + BRepBndLib::Add( face, bbox ); + double farTol = 0.01 * sqrt( bbox.SquareExtent() ); for ( size_t iP = 0; iP < points.size(); ++iP ) { @@ -4206,7 +4414,7 @@ bool StdMeshers_Quadrangle_2D::getEnforcedUV() << points[ iP ].X() << ", "<< points[ iP ].Y() << ", "<< points[ iP ].Z() << " )"); continue; } - if ( project.LowerDistance() > tol*1000 ) + if ( project.LowerDistance() > farTol ) { if ( isStrictCheck && iP < nbPoints ) return error @@ -4577,6 +4785,9 @@ int StdMeshers_Quadrangle_2D::splitQuad(FaceQuadStruct::Ptr quad, int I, int J) return QUAD_TOP_SIDE; } + + myQuadList.pop_back(); + return -1; } //================================================================================