From 3a82c6685ba4ebb801901e8330428030a65180cd Mon Sep 17 00:00:00 2001 From: eap Date: Tue, 23 Mar 2010 08:04:58 +0000 Subject: [PATCH] 020676: EDF 1212 GEOM: Partition operation creates vertices which causes mesh computation to fail with netgen * Cash GeomAPI_ProjectPointOnSurf's * Make applyFunc() public under name applyIn2D() + * \brief Define a pointer to wrapper over a function of gp_XY class, + * suitable to pass as xyFunPtr to applyIn2D(). + * For exaple gp_XY_FunPtr(Added) defines pointer gp_XY_Added to function + * calling gp_XY::Added(gp_XY), which is to be used like following + * applyIn2D(surf, uv1, uv2, gp_XY_Added) + */ +#define gp_XY_FunPtr(meth) \ + static gp_XY __gpXY_##meth (const gp_XY& uv1, const gp_XY& uv2) { return uv1.meth( uv2 ); } \ + static xyFunPtr gp_XY_##meth = & __gpXY_##meth + /*! + * \brief Perform given operation on two 2d points in parameric space of given surface. + * It takes into account period of the surface. Use gp_XY_FunPtr macro + * to easily define pointer to function of gp_XY class. + */ + static gp_XY applyIn2D(const Handle(Geom_Surface)& surface, + const gp_XY& uv1, + const gp_XY& uv2, + xyFunPtr fun, + const bool resultInPeriod=true); + --- src/SMESH/SMESH_MesherHelper.cxx | 131 +++++++++++++++++++------------ src/SMESH/SMESH_MesherHelper.hxx | 38 +++++++++ 2 files changed, 118 insertions(+), 51 deletions(-) diff --git a/src/SMESH/SMESH_MesherHelper.cxx b/src/SMESH/SMESH_MesherHelper.cxx index 3c92c01f1..1647d0a46 100644 --- a/src/SMESH/SMESH_MesherHelper.cxx +++ b/src/SMESH/SMESH_MesherHelper.cxx @@ -79,6 +79,18 @@ SMESH_MesherHelper::SMESH_MesherHelper(SMESH_Mesh& theMesh) mySetElemOnShape = ( ! myMesh->HasShapeToMesh() ); } +//======================================================================= +//function : ~SMESH_MesherHelper +//purpose : +//======================================================================= + +SMESH_MesherHelper::~SMESH_MesherHelper() +{ + TID2Projector::iterator i_proj = myFace2Projector.begin(); + for ( ; i_proj != myFace2Projector.end(); ++i_proj ) + delete i_proj->second; +} + //======================================================================= //function : IsQuadraticSubMesh //purpose : Check submesh for given shape: if all elements on this shape @@ -467,7 +479,8 @@ bool SMESH_MesherHelper::CheckNodeUV(const TopoDS_Face& F, nodePnt.Distance( surface->Value( uv.X(), uv.Y() )) > tol ) { // uv incorrect, project the node to surface - GeomAPI_ProjectPointOnSurf projector( nodePnt, surface, tol ); + GeomAPI_ProjectPointOnSurf& projector = GetProjector( F, loc, tol ); + projector.Perform( nodePnt ); if ( !projector.IsDone() || projector.NbPoints() < 1 ) { MESSAGE( "SMESH_MesherHelper::CheckNodeUV() failed to project" ); @@ -490,61 +503,77 @@ bool SMESH_MesherHelper::CheckNodeUV(const TopoDS_Face& F, return true; } -namespace +//======================================================================= +//function : GetProjector +//purpose : Return projector intitialized by given face without location, which is returned +//======================================================================= + +GeomAPI_ProjectPointOnSurf& SMESH_MesherHelper::GetProjector(const TopoDS_Face& F, + TopLoc_Location& loc, + double tol ) const { - struct TMiddle + Handle(Geom_Surface) surface = BRep_Tool::Surface( F,loc ); + int faceID = GetMeshDS()->ShapeToIndex( F ); + TID2Projector& i2proj = const_cast< TID2Projector&>( myFace2Projector ); + TID2Projector::iterator i_proj = i2proj.find( faceID ); + if ( i_proj == i2proj.end() ) { - gp_XY operator()(const gp_XY& uv1, const gp_XY& uv2) const { return ( uv1 + uv2 ) / 2.; } - }; - struct TAdd - { - gp_XY operator()(const gp_XY& uv1, const gp_XY& uv2) const { return ( uv1 + uv2 ); } - }; - struct TSubtract - { - gp_XY operator()(const gp_XY& uv1, const gp_XY& uv2) const { return ( uv1 - uv2 ); } - }; + if ( tol == 0 ) tol = BRep_Tool::Tolerance( F ); + double U1, U2, V1, V2; + surface->Bounds(U1, U2, V1, V2); + GeomAPI_ProjectPointOnSurf* proj = new GeomAPI_ProjectPointOnSurf(); + proj->Init( surface, U1, U2, V1, V2, tol ); + i_proj = i2proj.insert( make_pair( faceID, proj )).first; + } + return *( i_proj->second ); +} - //================================================================================ - /*! - * \brief Perform given operation on two points in parametric space of given surface - * Example: gp_XY uvSum = applyXYFUN( surf, uv1, uv2, gp_XYFun(Added)) - */ - //================================================================================ +namespace +{ + gp_XY AverageUV(const gp_XY& uv1, const gp_XY& uv2) { return ( uv1 + uv2 ) / 2.; } + gp_XY_FunPtr(Added); // define gp_XY_Added pointer to function calling gp_XY::Added(gp_XY) + gp_XY_FunPtr(Subtracted); +} - template - gp_XY applyFunc(const Handle(Geom_Surface)& surface, - const gp_XY& uv1, - gp_XY uv2, - const bool resultInPeriod=true) - { - Standard_Boolean isUPeriodic = surface.IsNull() ? false : surface->IsUPeriodic(); - Standard_Boolean isVPeriodic = surface.IsNull() ? false : surface->IsVPeriodic(); - if ( !isUPeriodic && !isVPeriodic ) - return FUNC()(uv1,uv2); +//======================================================================= +//function : applyIn2D +//purpose : Perform given operation on two 2d points in parameric space of given surface. +// It takes into account period of the surface. Use gp_XY_FunPtr macro +// to easily define pointer to function of gp_XY class. +//======================================================================= - // move uv2 not far than half-period from uv1 +gp_XY SMESH_MesherHelper::applyIn2D(const Handle(Geom_Surface)& surface, + const gp_XY& uv1, + const gp_XY& uv2, + xyFunPtr fun, + const bool resultInPeriod) +{ + Standard_Boolean isUPeriodic = surface.IsNull() ? false : surface->IsUPeriodic(); + Standard_Boolean isVPeriodic = surface.IsNull() ? false : surface->IsVPeriodic(); + if ( !isUPeriodic && !isVPeriodic ) + return fun(uv1,uv2); + + // move uv2 not far than half-period from uv1 + double u2 = + uv2.X()+(isUPeriodic ? ShapeAnalysis::AdjustByPeriod(uv2.X(),uv1.X(),surface->UPeriod()) :0); + double v2 = + uv2.Y()+(isVPeriodic ? ShapeAnalysis::AdjustByPeriod(uv2.Y(),uv1.Y(),surface->VPeriod()) :0); + + // execute operation + gp_XY res = fun( uv1, gp_XY(u2,v2) ); + + // move result within period + if ( resultInPeriod ) + { + Standard_Real UF,UL,VF,VL; + surface->Bounds(UF,UL,VF,VL); if ( isUPeriodic ) - uv2.SetX( uv2.X()+ShapeAnalysis::AdjustByPeriod(uv2.X(),uv1.X(),surface->UPeriod()) ); + res.SetX( res.X() + ShapeAnalysis::AdjustToPeriod(res.X(),UF,UL)); if ( isVPeriodic ) - uv2.SetY( uv2.Y()+ShapeAnalysis::AdjustByPeriod(uv2.Y(),uv1.Y(),surface->VPeriod()) ); - - // execute operation - gp_XY res = FUNC()(uv1,uv2); - - // move result within period - if ( resultInPeriod ) - { - Standard_Real UF,UL,VF,VL; - surface->Bounds(UF,UL,VF,VL); - if ( isUPeriodic ) - res.SetX( res.X() + ShapeAnalysis::AdjustToPeriod(res.X(),UF,UL)); - if ( isVPeriodic ) - res.SetY( res.Y() + ShapeAnalysis::AdjustToPeriod(res.Y(),VF,VL)); - } - - return res; + res.SetY( res.Y() + ShapeAnalysis::AdjustToPeriod(res.Y(),VF,VL)); } + + return res; } //======================================================================= //function : GetMiddleUV @@ -555,7 +584,7 @@ gp_XY SMESH_MesherHelper::GetMiddleUV(const Handle(Geom_Surface)& surface, const gp_XY& p1, const gp_XY& p2) { - return applyFunc( surface, p1, p2 ); + return applyIn2D( surface, p1, p2, & AverageUV ); } //======================================================================= @@ -2585,7 +2614,7 @@ void SMESH_MesherHelper::FixQuadraticElements(bool volumeOnly) gp_XY uv2 = GetNodeUV( face, link->node2(), nodeOnFace, &checkUV); gp_XY uv12 = GetMiddleUV( surf, uv1, uv2); // uvMove = uvm - uv12 - gp_XY uvMove = applyFunc(surf, uvm, uv12,/*inPeriod=*/false); + gp_XY uvMove = applyIn2D(surf, uvm, uv12, gp_XY_Subtracted, /*inPeriod=*/false); ( is1 ? move1 : move0 ).SetCoord( uvMove.X(), uvMove.Y(), 0 ); } if ( move0.SquareMagnitude() < straightTol2 && @@ -2633,7 +2662,7 @@ void SMESH_MesherHelper::FixQuadraticElements(bool volumeOnly) // compute 3D displacement by 2D one Handle(Geom_Surface) s = BRep_Tool::Surface(face,loc); gp_XY oldUV = GetNodeUV( face, (*link1)->_mediumNode, 0, &checkUV); - gp_XY newUV = applyFunc( s, oldUV, gp_XY( move.X(),move.Y() )); + gp_XY newUV = applyIn2D( s, oldUV, gp_XY( move.X(),move.Y()), gp_XY_Added); gp_Pnt newPnt = s->Value( newUV.X(), newUV.Y()); move = gp_Vec( XYZ((*link1)->_mediumNode), newPnt.Transformed(loc) ); #ifdef _DEBUG_ diff --git a/src/SMESH/SMESH_MesherHelper.hxx b/src/SMESH/SMESH_MesherHelper.hxx index c9305b909..c4623a57a 100644 --- a/src/SMESH/SMESH_MesherHelper.hxx +++ b/src/SMESH/SMESH_MesherHelper.hxx @@ -39,6 +39,8 @@ #include +class GeomAPI_ProjectPointOnSurf; + typedef std::map TLinkNodeMap; typedef std::map::iterator ItTLinkNode; @@ -48,6 +50,8 @@ typedef boost::shared_ptr< PShapeIterator > PShapeIteratorPtr; typedef std::vector TNodeColumn; typedef std::map< double, TNodeColumn > TParam2ColumnMap; +typedef gp_XY (*xyFunPtr)(const gp_XY& uv1, const gp_XY& uv2); + //======================================================================= /*! * \brief It helps meshers to add elements @@ -294,6 +298,28 @@ public: static gp_XY GetMiddleUV(const Handle(Geom_Surface)& surface, const gp_XY& uv1, const gp_XY& uv2); + /*! + * \brief Define a pointer to wrapper over a function of gp_XY class, + * suitable to pass as xyFunPtr to applyIn2D(). + * For exaple gp_XY_FunPtr(Added) defines pointer gp_XY_Added to function + * calling gp_XY::Added(gp_XY), which is to be used like following + * applyIn2D(surf, uv1, uv2, gp_XY_Added) + */ +#define gp_XY_FunPtr(meth) \ + static gp_XY __gpXY_##meth (const gp_XY& uv1, const gp_XY& uv2) { return uv1.meth( uv2 ); } \ + static xyFunPtr gp_XY_##meth = & __gpXY_##meth + + /*! + * \brief Perform given operation on two 2d points in parameric space of given surface. + * It takes into account period of the surface. Use gp_XY_FunPtr macro + * to easily define pointer to function of gp_XY class. + */ + static gp_XY applyIn2D(const Handle(Geom_Surface)& surface, + const gp_XY& uv1, + const gp_XY& uv2, + xyFunPtr fun, + const bool resultInPeriod=true); + /*! * \brief Check if inFaceNode argument is necessary for call GetNodeUV(F,..) * \retval bool - return true if the face is periodic @@ -303,6 +329,13 @@ public: */ bool GetNodeUVneedInFaceNode(const TopoDS_Face& F = TopoDS_Face()) const; + /*! + * \brief Return projector intitialized by given face without location, which is returned + */ + GeomAPI_ProjectPointOnSurf& GetProjector(const TopoDS_Face& F, + TopLoc_Location& loc, + double tol=0 ) const; + /*! * \brief Check if shape is a degenerated edge or it's vertex * \param subShape - edge or vertex index in SMESHDS @@ -401,6 +434,8 @@ public: enum MType{ LINEAR, QUADRATIC, COMP }; MType IsQuadraticMesh(); + virtual ~SMESH_MesherHelper(); + protected: /*! @@ -424,6 +459,9 @@ protected: double myPar1[2], myPar2[2]; // U and V bounds of a closed periodic surface int myParIndex; // bounds' index (1-U, 2-V, 3-both) + typedef std::map< int, GeomAPI_ProjectPointOnSurf* > TID2Projector; + TID2Projector myFace2Projector; + TopoDS_Shape myShape; SMESH_Mesh* myMesh; int myShapeID; -- 2.39.2