From: eap Date: Wed, 15 Dec 2010 10:43:22 +0000 (+0000) Subject: 0020832: EDF 1359 SMESH : Automatic meshing of boundary layers X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=0c3ea600d81889e3a5b182dcffcc8c6ae586049e;p=modules%2Fsmesh.git 0020832: EDF 1359 SMESH : Automatic meshing of boundary layers Prototype version + * interface of "Viscous Layers" hypothesis. + * This hypothesis specifies parameters of layers of prisms to build + * near mesh boundary. This hypothesis can be used by several 3D algorithms: + * NETGEN 3D, GHS3D, Hexahedron(i,j,k), 3D Extrusion, Radial Prism + */ + interface StdMeshers_ViscousLayers : SMESH::SMESH_Hypothesis --- diff --git a/idl/SMESH_BasicHypothesis.idl b/idl/SMESH_BasicHypothesis.idl index 88b0ab751..ada4be5e4 100644 --- a/idl/SMESH_BasicHypothesis.idl +++ b/idl/SMESH_BasicHypothesis.idl @@ -838,6 +838,39 @@ module StdMeshers void GetCopySourceMesh(out boolean toCopyMesh,out boolean toCopyGroups); }; + /*! + * interface of "Viscous Layers" hypothesis. + * This hypothesis specifies parameters of layers of prisms to build + * near mesh boundary. This hypothesis can be used by several 3D algorithms: + * NETGEN 3D, GHS3D, Hexahedron(i,j,k), 3D Extrusion, Radial Prism + */ + interface StdMeshers_ViscousLayers : SMESH::SMESH_Hypothesis + { + /*! + * Set faces to exclude from treatment + */ + void SetIgnoreFaces(in SMESH::long_array faceIDs) raises (SALOME::SALOME_Exception); + SMESH::long_array GetIgnoreFaces(); + + /*! + * Set total thickness of layers of prisms + */ + void SetTotalThickness(in double thickness) raises (SALOME::SALOME_Exception); + double GetTotalThickness(); + + /*! + * Set number of layers of prisms + */ + void SetNumberLayers(in short nb) raises (SALOME::SALOME_Exception); + short GetNumberLayers(); + + /*! + * Set factor (>1.0) of growth of layer thickness towards inside of mesh + */ + void SetStretchFactor(in double factor) raises (SALOME::SALOME_Exception); + double GetStretchFactor(); + }; + /*! * StdMeshers_SegmentAroundVertex_0D: interface of "SegmentAroundVertex" algorithm */ diff --git a/resources/StdMeshers.xml b/resources/StdMeshers.xml index 41c83c997..6cd63a5ee 100644 --- a/resources/StdMeshers.xml +++ b/resources/StdMeshers.xml @@ -159,6 +159,12 @@ icon-id="mesh_hypo_length.png" dim="3"/> + + 1.0) of growth of layer thickness towards inside of mesh + # @param ignoreFaces geometrical face (or their ids) not to generate layers on + # @ingroup l3_hypos_additi + def ViscousLayers(self, thickness, numberOfLayers, stretchFactor, ignoreFaces=[]): + if not isinstance(self.algo, SMESH._objref_SMESH_3D_Algo): + raise TypeError, "ViscousLayers are supported by 3D algorithms only" + if not "ViscousLayers" in self.GetCompatibleHypothesis(): + raise TypeError, "ViscousLayers are not supported by %s"%self.algo.GetName() + if ignoreFaces and isinstance( ignoreFaces[0], geompyDC.GEOM._objref_GEOM_Object ): + ignoreFaces = [ self.mesh.geompyD.GetSubShapeID(self.mesh.geom, f) for f in ignoreFaces ] + hyp = self.Hypothesis("ViscousLayers", + [thickness, numberOfLayers, stretchFactor, ignoreFaces]) + hyp.SetTotalThickness(thickness) + hyp.SetNumberLayers(numberOfLayers) + hyp.SetStretchFactor(stretchFactor) + hyp.SetIgnoreFaces(ignoreFaces) + return hyp + # Public class: Mesh_Segment # -------------------------- diff --git a/src/StdMeshers/Makefile.am b/src/StdMeshers/Makefile.am index 08c312ead..6e02bb7bc 100644 --- a/src/StdMeshers/Makefile.am +++ b/src/StdMeshers/Makefile.am @@ -75,7 +75,9 @@ salomeinclude_HEADERS = \ StdMeshers_HexaFromSkin_3D.hxx \ StdMeshers_ImportSource.hxx \ StdMeshers_Import_1D.hxx \ - StdMeshers_Import_1D2D.hxx + StdMeshers_Import_1D2D.hxx \ + StdMeshers_ViscousLayers.hxx \ + StdMeshers_ProxyMesh.hxx # Libraries targets @@ -129,8 +131,9 @@ dist_libStdMeshers_la_SOURCES = \ StdMeshers_HexaFromSkin_3D.cxx \ StdMeshers_ImportSource.cxx \ StdMeshers_Import_1D.cxx \ - StdMeshers_Import_1D2D.cxx - + StdMeshers_Import_1D2D.cxx \ + StdMeshers_ViscousLayers.cxx \ + StdMeshers_ProxyMesh.cxx # additionnal information to compil and link file libStdMeshers_la_CPPFLAGS = \ diff --git a/src/StdMeshers/StdMeshers_ProxyMesh.cxx b/src/StdMeshers/StdMeshers_ProxyMesh.cxx new file mode 100644 index 000000000..4dc21a5fd --- /dev/null +++ b/src/StdMeshers/StdMeshers_ProxyMesh.cxx @@ -0,0 +1,384 @@ +// Copyright (C) 2007-2010 CEA/DEN, EDF R&D, OPEN CASCADE +// +// 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_ProxyMesh.cxx +// Created : Thu Dec 2 12:32:53 2010 +// Author : Edward AGAPOV (eap) + +#include "StdMeshers_ProxyMesh.hxx" + +#include "SMDS_IteratorOnIterators.hxx" +#include "SMDS_SetIterator.hxx" +#include "SMESH_MesherHelper.hxx" + +#include +#include + +//================================================================================ +/*! + * \brief Constructor; mesh must be set by a descendant class + */ +//================================================================================ + +StdMeshers_ProxyMesh::StdMeshers_ProxyMesh():_mesh(0) +{ +} +//================================================================================ +/*! + * \brief Make a proxy mesh from components. Components become empty + */ +//================================================================================ + +StdMeshers_ProxyMesh::StdMeshers_ProxyMesh(vector& components) +{ + if ( components.empty() ) return; + + for ( unsigned i = 0; i < components.size(); ++i ) + { + StdMeshers_ProxyMesh* m = components[i].get(); + + if ( !_mesh ) _mesh = m->_mesh; + if ( _allowedTypes.empty() ) _allowedTypes = m->_allowedTypes; + + if ( _subMeshes.size() < m->_subMeshes.size() ) + _subMeshes.resize( m->_subMeshes.size(), 0 ); + for ( unsigned j = 0; j < m->_subMeshes.size(); ++j ) + { + if ( !m->_subMeshes[j] ) continue; + if ( _subMeshes[j] ) + { + // unite 2 sub-meshes + set< const SMDS_MeshElement * > elems( _subMeshes[j]->_elements.begin(), + _subMeshes[j]->_elements.end()); + elems.insert( m->_subMeshes[j]->_elements.begin(), + m->_subMeshes[j]->_elements.end()); + _subMeshes[j]->_elements.assign( elems.begin(), elems.end() ); + + if ( !_subMeshes[j]->_n2n ) + _subMeshes[j]->_n2n = m->_subMeshes[j]->_n2n, m->_subMeshes[j]->_n2n = 0; + + else if ( _subMeshes[j]->_n2n && m->_subMeshes[j]->_n2n ) + _subMeshes[j]->_n2n->insert( m->_subMeshes[j]->_n2n->begin(), + m->_subMeshes[j]->_n2n->end()); + } + else + { + _subMeshes[j] = m->_subMeshes[j]; + m->_subMeshes[j] = 0; + } + } + } +} + +//================================================================================ +/*! + * \brief Destructor deletes proxy submeshes + */ +//================================================================================ + +StdMeshers_ProxyMesh::~StdMeshers_ProxyMesh() +{ + for ( unsigned i = 0; i < _subMeshes.size(); ++i ) + delete _subMeshes[i]; + _subMeshes.clear(); +} + +//================================================================================ +/*! + * \brief Returns index of a shape + */ +//================================================================================ + +int StdMeshers_ProxyMesh::shapeIndex(const TopoDS_Shape& shape) const +{ + return ( shape.IsNull() || !_mesh->HasShapeToMesh() ? 0 : getMeshDS()->ShapeToIndex(shape)); +} + +//================================================================================ +/*! + * \brief Returns the submesh of a shape; it can be a proxy sub-mesh + */ +//================================================================================ + +const SMESHDS_SubMesh* StdMeshers_ProxyMesh::GetSubMesh(const TopoDS_Shape& shape) const +{ + const SMESHDS_SubMesh* sm = 0; + + int i = shapeIndex(shape); + if ( i < _subMeshes.size() ) + sm = _subMeshes[i]; + if ( !sm ) + sm = getMeshDS()->MeshElements( i ); + + return sm; +} + +//================================================================================ +/*! + * \brief Returns the proxy sub-mesh of a shape; it can be NULL + */ +//================================================================================ + +const StdMeshers_ProxyMesh::SubMesh* +StdMeshers_ProxyMesh::GetProxySubMesh(const TopoDS_Shape& shape) const +{ + int i = shapeIndex(shape); + return i < _subMeshes.size() ? _subMeshes[i] : 0; +} + +//================================================================================ +/*! + * \brief Returns the proxy node of a node; the input node is returned if no proxy exists + */ +//================================================================================ + +const SMDS_MeshNode* StdMeshers_ProxyMesh::GetProxyNode( const SMDS_MeshNode* node ) const +{ + const SMDS_MeshNode* proxy = node; + if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE ) + { + if ( const SubMesh* proxySM = findProxySubMesh( node->GetPosition()->GetShapeId() )) + proxy = proxySM->GetProxyNode( node ); + } + else + { + TopoDS_Shape shape = SMESH_MesherHelper::GetSubShapeByNode( node, getMeshDS()); + TopTools_ListIteratorOfListOfShape ancIt; + if ( !shape.IsNull() ) ancIt.Initialize( _mesh->GetAncestors( shape )); + for ( ; ancIt.More() && proxy == node; ancIt.Next() ) + if ( const SubMesh* proxySM = findProxySubMesh( shapeIndex(ancIt.Value()))) + proxy = proxySM->GetProxyNode( node ); + } + return proxy; +} + +namespace +{ + //================================================================================ + /*! + * \brief Iterator filtering elements by type + */ + //================================================================================ + + class TFilteringIterator : public SMDS_ElemIterator + { + SMDS_ElemIteratorPtr _iter; + const SMDS_MeshElement * _curElem; + vector< SMDSAbs_EntityType> _okTypes; + public: + TFilteringIterator( const vector< SMDSAbs_EntityType>& okTypes, + const SMDS_ElemIteratorPtr& elemIterator) + :_iter(elemIterator), _curElem(0), _okTypes(okTypes) + { + } + virtual bool more() + { + return _curElem; + } + virtual const SMDS_MeshElement* next() + { + const SMDS_MeshElement* res = _curElem; + _curElem = 0; + while ( _iter->more() && !_curElem ) + { + _curElem = _iter->next(); + if ( find( _okTypes.begin(), _okTypes.end(), _curElem->GetEntityType()) != _okTypes.end()) + _curElem = 0; + } + return res; + } + }; +} + +//================================================================================ +/*! + * \brief Returns iterator on all faces on the shape taking into account substitutions + */ +//================================================================================ + +SMDS_ElemIteratorPtr StdMeshers_ProxyMesh::GetFaces(const TopoDS_Shape& shape) const +{ + if ( !_mesh->HasShapeToMesh() ) + return SMDS_ElemIteratorPtr(); + + _subContainer.RemoveAllSubmeshes(); + + TopExp_Explorer fExp( shape, TopAbs_FACE ); + for ( ; fExp.More(); fExp.Next() ) + if ( const SMESHDS_SubMesh* sm = GetSubMesh( fExp.Current())) + _subContainer.AddSubMesh( sm ); + return _subContainer.GetElements(); +} + +//================================================================================ +/*! + * \brief Returns iterator on all faces of the mesh taking into account substitutions + * To be used in case of mesh without shape + */ +//================================================================================ + +SMDS_ElemIteratorPtr StdMeshers_ProxyMesh::GetFaces() const +{ + if ( _mesh->HasShapeToMesh() ) + return SMDS_ElemIteratorPtr(); + + _subContainer.RemoveAllSubmeshes(); + for ( unsigned i = 0; i < _subMeshes.size(); ++i ) + if ( _subMeshes[i] ) + _subContainer.AddSubMesh( _subMeshes[i] ); + + if ( _subContainer.NbSubMeshes() == 0 ) // no elements substituted + return getMeshDS()->elementsIterator(SMDSAbs_Face); + + // if _allowedTypes is empty, only elements from _subMeshes are returned,... + SMDS_ElemIteratorPtr proxyIter = _subContainer.GetElements(); + if ( _allowedTypes.empty() || NbFaces() == _mesh->NbFaces() ) + return proxyIter; + + // ... else elements filtered using allowedTypes are additionally returned + SMDS_ElemIteratorPtr facesIter = getMeshDS()->elementsIterator(SMDSAbs_Face); + SMDS_ElemIteratorPtr filterIter( new TFilteringIterator( _allowedTypes, facesIter )); + vector< SMDS_ElemIteratorPtr > iters(2); + iters[0] = proxyIter; + iters[1] = filterIter; + + typedef vector< SMDS_ElemIteratorPtr > TElemIterVector; + typedef SMDS_IteratorOnIterators TItersIter; + return SMDS_ElemIteratorPtr( new TItersIter( iters )); +} + +//================================================================================ +/*! + * \brief Return total nb of faces taking into account substitutions + */ +//================================================================================ + +int StdMeshers_ProxyMesh::NbFaces() const +{ + // TODO +} + +//================================================================================ +/*! + * \brief Returns a proxy sub-mesh; it is created if not yet exists + */ +//================================================================================ + +StdMeshers_ProxyMesh::SubMesh* StdMeshers_ProxyMesh::getProxySubMesh(int index) +{ + if ( int(_subMeshes.size()) <= index ) + _subMeshes.resize( index+1, 0 ); + if ( !_subMeshes[index] ) + _subMeshes[index] = new SubMesh; + return _subMeshes[index]; +} + +//================================================================================ +/*! + * \brief Returns a proxy sub-mesh; it is created if not yet exists + */ +//================================================================================ + +StdMeshers_ProxyMesh::SubMesh* StdMeshers_ProxyMesh::getProxySubMesh(const TopoDS_Shape& shape) +{ + return getProxySubMesh( shapeIndex( shape )); +} + +//================================================================================ +/*! + * \brief Returns a proxy sub-mesh + */ +//================================================================================ + +StdMeshers_ProxyMesh::SubMesh* StdMeshers_ProxyMesh::findProxySubMesh(int shapeIndex) const +{ + return shapeIndex < int(_subMeshes.size()) ? _subMeshes[shapeIndex] : 0; +} + +//================================================================================ +/*! + * \brief Returns mesh DS + */ +//================================================================================ + +const SMESHDS_Mesh* StdMeshers_ProxyMesh::getMeshDS() const +{ + return _mesh ? _mesh->GetMeshDS() : 0; +} + +//================================================================================ +/*! + * \brief Return a proxy node or an input node + */ +//================================================================================ + +const SMDS_MeshNode* StdMeshers_ProxyMesh::SubMesh::GetProxyNode( const SMDS_MeshNode* n ) const +{ + TN2NMap::iterator n2n; + if ( _n2n && ( n2n = _n2n->find( n )) != _n2n->end()) + return n2n->second; + return n; +} + +//================================================================================ +/*! + * \brief Deletes temporary elements + */ +//================================================================================ + +void StdMeshers_ProxyMesh::SubMesh::Clear() +{ + for ( unsigned i = 0; i < _elements.size(); ++i ) + if ( _elements[i]->GetID() > 0 ) + delete _elements[i]; + _elements.clear(); +} + +//================================================================================ +/*! + * \brief Return number of elements in a proxy submesh + */ +//================================================================================ + +int StdMeshers_ProxyMesh::SubMesh::NbElements() const +{ + return _elements.size(); +} + +//================================================================================ +/*! + * \brief Return elements of a proxy submesh + */ +//================================================================================ + +SMDS_ElemIteratorPtr StdMeshers_ProxyMesh::SubMesh::GetElements() const +{ + return SMDS_ElemIteratorPtr + ( new SMDS_ElementVectorIterator( _elements.begin(), _elements.end() )); +} + +//================================================================================ +/*! + * \brief Store an element + */ +//================================================================================ + +void StdMeshers_ProxyMesh::SubMesh::AddElement(const SMDS_MeshElement * e) +{ + _elements.push_back( e ); +} diff --git a/src/StdMeshers/StdMeshers_ProxyMesh.hxx b/src/StdMeshers/StdMeshers_ProxyMesh.hxx new file mode 100644 index 000000000..dd24b28ee --- /dev/null +++ b/src/StdMeshers/StdMeshers_ProxyMesh.hxx @@ -0,0 +1,139 @@ +// Copyright (C) 2007-2010 CEA/DEN, EDF R&D, OPEN CASCADE +// +// 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_ProxyMesh.hxx +// Created : Thu Dec 2 10:05:35 2010 +// Author : Edward AGAPOV (eap) + +#ifndef __StdMeshers_ProxyMesh_HXX__ +#define __StdMeshers_ProxyMesh_HXX__ + +#include "SMESH_StdMeshers.hxx" + +#include "SMDS_MeshElement.hxx" +#include "SMESHDS_SubMesh.hxx" + +#include + +#include +#include +#include + +class SMDS_MeshNode; +class SMESHDS_Mesh; +class SMESH_Mesh; + +/*! + * \brief Container of mesh faces substituting other faces in the input mesh of 3D algorithm + */ +class STDMESHERS_EXPORT StdMeshers_ProxyMesh +{ +public: + + typedef boost::shared_ptr Ptr; + + typedef std::map TN2NMap; + + //-------------------------------------------------------------------------------- + /*! + * \brief Proxy sub-mesh + */ + class SubMesh : public SMESHDS_SubMesh + { + public: + + const TN2NMap* GetNodeNodeMap() const { return _n2n; } + const SMDS_MeshNode* GetProxyNode( const SMDS_MeshNode* n ) const; + virtual void AddElement(const SMDS_MeshElement * e); + virtual int NbElements() const; + virtual SMDS_ElemIteratorPtr GetElements() const; + virtual void Clear(); + + SubMesh():_n2n(0) {} + ~SubMesh() { Clear(); } + + protected: + std::vector _elements; + TN2NMap* _n2n; + friend class StdMeshers_ProxyMesh; + }; + //-------------------------------------------------------------------------------- + // Public interface + + StdMeshers_ProxyMesh(); + StdMeshers_ProxyMesh(std::vector& components); + virtual ~StdMeshers_ProxyMesh(); + + // Returns the submesh of a face; it can be a proxy sub-mesh + const SMESHDS_SubMesh* GetSubMesh(const TopoDS_Shape& face) const; + + // Returns the proxy sub-mesh of a face; it can be NULL + const SubMesh* GetProxySubMesh(const TopoDS_Shape& face) const; + + // Returns the proxy node of a node; the input node is returned if no proxy exists + const SMDS_MeshNode* GetProxyNode( const SMDS_MeshNode* node ) const; + + // Returns iterator on all faces of the mesh taking into account substitutions + // To be used in case of mesh without shape + SMDS_ElemIteratorPtr GetFaces() const; + + // Returns iterator on all faces on the face taking into account substitutions + SMDS_ElemIteratorPtr GetFaces(const TopoDS_Shape& face) const; + + // Return total nb of faces taking into account substitutions + int NbFaces() const; + + + //-------------------------------------------------------------------------------- + // Interface for descendants + protected: + + void setMesh(const SMESH_Mesh& mesh) { _mesh = &mesh; } + + const SMESHDS_Mesh* getMeshDS() const; + + int shapeIndex(const TopoDS_Shape& shape) const; + + // returns a proxy sub-mesh; zero index is for the case of mesh w/o shape + SubMesh* findProxySubMesh(int shapeIndex=0) const; + + // returns a proxy sub-mesh; it is created if not yet exists + SubMesh* getProxySubMesh(int shapeIndex=0); + + // returns a proxy sub-mesh; it is created if not yet exists + SubMesh* getProxySubMesh(const TopoDS_Shape& shape=TopoDS_Shape()); + + + private: + + const SMESH_Mesh* _mesh; + + // proxy sub-meshes; index in vector == shapeIndex(shape) + std::vector< SubMesh* > _subMeshes; + + // types of elements needed to implement NbFaces() and GetFaces(); + // if _allowedTypes is empty, only elements from _subMeshes are returned, + // else elements of _mesh filtered using allowedTypes are additionally returned + std::vector< SMDSAbs_EntityType> _allowedTypes; + + // Complex submesh used to iterate over elements in other sub-meshes + mutable SubMesh _subContainer; +}; + +#endif diff --git a/src/StdMeshers/StdMeshers_ViscousLayers.cxx b/src/StdMeshers/StdMeshers_ViscousLayers.cxx new file mode 100644 index 000000000..63f44338a --- /dev/null +++ b/src/StdMeshers/StdMeshers_ViscousLayers.cxx @@ -0,0 +1,2022 @@ +// Copyright (C) 2007-2011 CEA/DEN, EDF R&D, OPEN CASCADE +// +// 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_ViscousLayers.cxx +// Created : Wed Dec 1 15:15:34 2010 +// Author : Edward AGAPOV (eap) + +#include "StdMeshers_ViscousLayers.hxx" + +#include "SMDS_EdgePosition.hxx" +#include "SMDS_FaceOfNodes.hxx" +#include "SMDS_FacePosition.hxx" +#include "SMDS_MeshNode.hxx" +#include "SMESHDS_Group.hxx" +#include "SMESHDS_Hypothesis.hxx" +#include "SMESH_Algo.hxx" +#include "SMESH_ComputeError.hxx" +#include "SMESH_Gen.hxx" +#include "SMESH_Group.hxx" +#include "SMESH_Mesh.hxx" +#include "SMESH_MesherHelper.hxx" +#include "SMESH_subMesh.hxx" +#include "SMESH_subMeshEventListener.hxx" +#include "StdMeshers_ProxyMesh.hxx" + +#include "utilities.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +using namespace std; + +//================================================================================ +namespace VISCOUS +{ + /*! + * \brief StdMeshers_ProxyMesh computed by _ViscousBuilder for a solid. + * It is stored in a SMESH_subMesh of the solid as SMESH_subMeshEventListenerData + */ + struct _MeshOfSolid : public StdMeshers_ProxyMesh, + public SMESH_subMeshEventListenerData + { + _MeshOfSolid( SMESH_Mesh* mesh):SMESH_subMeshEventListenerData( /*isDeletable=*/true) + { + StdMeshers_ProxyMesh::setMesh( *mesh ); + } + + // returns submesh for a geom face + StdMeshers_ProxyMesh::SubMesh* getFaceData(const TopoDS_Face& F, bool create=false) + { + int i = StdMeshers_ProxyMesh::shapeIndex(F); + return create ? StdMeshers_ProxyMesh::getProxySubMesh(i) : findProxySubMesh(i); + } + }; + //-------------------------------------------------------------------------------- + /*! + * \brief Listener of events of 3D sub-meshes computed with viscous layers. + * It is used to store data computed by _ViscousBuilder for a sub-mesh and to + * delete the data as soon as it has been used + */ + struct _ViscousListener : SMESH_subMeshEventListener + { + _ViscousListener(): SMESH_subMeshEventListener(/*isDeletable=*/false) {} + static SMESH_subMeshEventListener* Get() { static _ViscousListener l; return &l; } + virtual void ProcessEvent(const int event, + const int eventType, + SMESH_subMesh* subMesh, + SMESH_subMeshEventListenerData* data, + const SMESH_Hypothesis* hyp) + { +// if ( SMESH_subMesh::COMPUTE == event && +// SMESH_subMesh::COMPUTE_EVENT == eventType ) + { + // delete StdMeshers_ProxyMesh containing temporary faces + subMesh->DeleteEventListener( _ViscousListener::Get() ); + } + } + static _MeshOfSolid* GetSolidMesh(SMESH_Mesh* mesh, + const TopoDS_Shape& solid, + bool toCreate=false) + { + if ( !mesh ) return 0; + SMESH_subMesh* sm = mesh->GetSubMesh(solid); + _MeshOfSolid* data = (_MeshOfSolid*) sm->GetEventListenerData( Get() ); + if ( !data && toCreate ) + ( data = new _MeshOfSolid(mesh)), sm->SetEventListener( Get(), data, sm ); + return data; + } + +// static void RemoveSolidMesh(SMESH_Mesh* mesh, +// const TopoDS_Shape& solid) +// { +// mesh->GetSubMesh(solid)->DeleteEventListener( _ViscousListener::Get() ); +// } + }; + //-------------------------------------------------------------------------------- + /*! + * \brief Simplex (triangle or tetrahedron) based on 1 (tria) or 2 (tet) nodes of + * _LayerEdge and 2 nodes of the mesh surface beening smoothed. + * The class is used to check validity of face or volumes around a smoothed node; + * it stores only 2 nodes as the other nodes are stored by _LayerEdge. + * For _LayerEdge on geom edge, _Simplex contains just two nodes of neighbour _LayerEdge + * basing on the same geom edge + */ + struct _Simplex + { + const SMDS_MeshNode *_nPrev, *_nNext; // nodes on a smoothed mesh surface + _Simplex(const SMDS_MeshNode* nPrev=0, const SMDS_MeshNode* nNext=0) + : _nPrev(nPrev), _nNext(nNext) {} + bool IsForward(const SMDS_MeshNode* nSrc, const gp_XYZ* pntTgt) const + { + const double M[3][3] = + {{ _nNext->X() - nSrc->X(), _nNext->Y() - nSrc->Y(), _nNext->Z() - nSrc->Z() }, + { pntTgt->X() - nSrc->X(), pntTgt->Y() - nSrc->Y(), pntTgt->Z() - nSrc->Z() }, + { _nPrev->X() - nSrc->X(), _nPrev->Y() - nSrc->Y(), _nPrev->Z() - nSrc->Z() }}; + double determinant = ( + M[0][0]*M[1][1]*M[2][2] + + M[0][1]*M[1][2]*M[2][0] + + M[0][2]*M[1][0]*M[2][1] + - M[0][0]*M[1][2]*M[2][1] + - M[0][1]*M[1][0]*M[2][2] + - M[0][2]*M[1][1]*M[2][0]); + return determinant > 1e-100; + } + bool IsForward(const gp_XY& tgtUV, + const TopoDS_Face& face, + SMESH_MesherHelper& helper, + const double refSign) const + { + gp_XY prevUV = helper.GetNodeUV( face, _nPrev ); + gp_XY nextUV = helper.GetNodeUV( face, _nNext ); + gp_Vec2d v1( tgtUV, prevUV ), v2( tgtUV, nextUV ); + double d = v1 ^ v2; + return d*refSign > 1e-100; + } + }; + //-------------------------------------------------------------------------------- + /*! + * \brief Edge normal to surface, connecting a node on solid surface (_nodes[0]) + * and a node of the most internal layer (_nodes.back()) + */ + struct _LayerEdge + { + vector< const SMDS_MeshNode*> _nodes; + + gp_XYZ _normal; // to solid surface + vector _pos; // points computed during inflation + double _len; // length achived with the last step + double _cosin; // of angle (_normal ^ surface) + + // face or edge w/o layer along or near which _LayerEdge is inflated + TopoDS_Shape _sWOL; + // simplices connected to _nodes[0]; for smoothing and quality check + // empty for edge inflating along _sWOL + vector<_Simplex> _simplices; + + void SetNewLength( double len, SMESH_MesherHelper& helper ); + void InvalidateStep( int curStep ); + bool Smooth(int& badNb); + bool Smooth2d(Handle(Geom_Surface)& surface, SMESH_MesherHelper& helper); + bool SegTriaInter( const gp_Ax1& lastSegment, + const SMDS_MeshNode* n0, + const SMDS_MeshNode* n1, + const SMDS_MeshNode* n2 ) const; + gp_Ax1 LastSegment() const; + bool IsOnEdge() const { return _simplices.size() == 1; } + }; + //-------------------------------------------------------------------------------- + + typedef map< const SMDS_MeshNode*, _LayerEdge*, TIDCompare > TNode2Edge; + + //-------------------------------------------------------------------------------- + /*! + * \brief Data of a SOLID + */ + struct _SolidData + { + TopoDS_Shape _solid; + const StdMeshers_ViscousLayers* _hyp; + _MeshOfSolid* _proxyMesh; + set _reversedFaceIds; + double _stepSize; + + TNode2Edge _n2eMap; + // edges of _n2eMap. We keep same data in two containers because + // iteration over the map is 5 time longer that over the vector + vector< _LayerEdge* > _edges; + + // key: an id of shape (edge or vertex) shared by a face with + // layers and a face w/o layers + // value: the shape (face or edge) to shrink mesh on. + // _LayerEdge's basing on nodes on key shape are inflated along the value shape + map< int, TopoDS_Shape > _shrinkShape2Shape; + + // end index in _edges of _LayerEdge's (map key) inflated along FACE (map value) + map< int, TopoDS_Face > _endEdge2Face; + + int _index; // for debug + + _SolidData(const TopoDS_Shape& s=TopoDS_Shape(), + const StdMeshers_ViscousLayers* h=0, + _MeshOfSolid* m=0) :_solid(s), _hyp(h), _proxyMesh(m) {} + ~_SolidData(); + }; + //-------------------------------------------------------------------------------- + /*! + * \brief Data of node on a shrinked face + */ + struct _SmoothNode + { + const SMDS_MeshNode* _node; + //vector _nodesAround; + vector<_Simplex> _simplices; // for quality check + + bool Smooth(int& badNb, + Handle(Geom_Surface)& surface, + TopLoc_Location& loc, + SMESH_MesherHelper& helper, + const double refSign); + }; + //-------------------------------------------------------------------------------- + /*! + * \brief Builder of viscous layers + */ + class _ViscousBuilder + { + public: + _ViscousBuilder(); + // does it's job + SMESH_ComputeErrorPtr Compute(SMESH_Mesh& mesh, const TopoDS_Shape& theShape); + + private: + + bool findSolidsWithLayers(); + bool findFacesWithLayers(); + bool makeLayer(_SolidData& data); + bool setEdgeData(_LayerEdge& edge, const set& subIds, + SMESH_MesherHelper& helper, _SolidData& data); + void getSimplices( const SMDS_MeshNode* node, vector<_Simplex>& simplices, + const set& ingnoreShapes, + const _SolidData* dataToCheckOri = 0); + bool inflate(_SolidData& data); + bool smoothAndCheck(_SolidData& data); + bool refine(_SolidData& data); + bool shrink(); + bool prepareEdgeToShrink( _LayerEdge& edge, const TopoDS_Face& F, + SMESH_MesherHelper& helper, + const SMESHDS_SubMesh* faceSubMesh ); + + bool error( string, _SolidData* data ); + SMESHDS_Mesh* getMeshDS() { return _mesh->GetMeshDS(); } + + // debug + void makeGroupOfLE(); + + SMESH_Mesh* _mesh; + SMESH_ComputeErrorPtr _error; + + vector< _SolidData > _sdVec; + set _ignoreShapeIds; + }; +} + +//================================================================================ +// StdMeshers_ViscousLayers hypothesis +// +StdMeshers_ViscousLayers::StdMeshers_ViscousLayers(int hypId, int studyId, SMESH_Gen* gen) + :SMESH_Hypothesis(hypId, studyId, gen), + _nbLayers(1), _thickness(1), _stretchFactor(1) +{ + _name = StdMeshers_ViscousLayers::GetHypType(); + _param_algo_dim = -3; // auxiliary hyp used by 3D algos +} // -------------------------------------------------------------------------------- +void StdMeshers_ViscousLayers::SetIgnoreFaces(const std::vector& faceIds) +{ + if ( faceIds != _ignoreFaceIds ) + _ignoreFaceIds = faceIds, NotifySubMeshesHypothesisModification(); +} // -------------------------------------------------------------------------------- +void StdMeshers_ViscousLayers::SetTotalThickness(double thickness) +{ + if ( thickness != _thickness ) + _thickness = thickness, NotifySubMeshesHypothesisModification(); +} // -------------------------------------------------------------------------------- +void StdMeshers_ViscousLayers::SetNumberLayers(int nb) +{ + if ( _nbLayers != nb ) + _nbLayers = nb, NotifySubMeshesHypothesisModification(); +} // -------------------------------------------------------------------------------- +void StdMeshers_ViscousLayers::SetStretchFactor(double factor) +{ + if ( _stretchFactor != factor ) + _stretchFactor = factor, NotifySubMeshesHypothesisModification(); +} // -------------------------------------------------------------------------------- +StdMeshers_ProxyMesh::Ptr StdMeshers_ViscousLayers::Compute(SMESH_Mesh& theMesh, + const TopoDS_Shape& theShape) const +{ + using namespace VISCOUS; + _ViscousBuilder bulder; + SMESH_ComputeErrorPtr err = bulder.Compute( theMesh, theShape ); + if ( err && !err->IsOK() ) + return StdMeshers_ProxyMesh::Ptr(); + + vector components; + TopExp_Explorer exp( theShape, TopAbs_SOLID ); + for ( ; exp.More(); exp.Next() ) + { + if ( _MeshOfSolid* pm = + _ViscousListener::GetSolidMesh( &theMesh, exp.Current(), /*toCreate=*/false)) + { + components.push_back( StdMeshers_ProxyMesh::Ptr( pm )); + pm->myIsDeletable =false; // it will de deleted by boost::shared_ptr + } + //_ViscousListener::RemoveSolidMesh ( &theMesh, exp.Current() ); + } + switch ( components.size() ) + { + case 0: break; + + case 1: return components[0]; + + default: return StdMeshers_ProxyMesh::Ptr( new StdMeshers_ProxyMesh( components )); + } + return StdMeshers_ProxyMesh::Ptr(); +} // -------------------------------------------------------------------------------- +std::ostream & StdMeshers_ViscousLayers::SaveTo(std::ostream & save) +{ + save << " " << _nbLayers + << " " << _thickness + << " " << _stretchFactor + << " " << _ignoreFaceIds.size(); + for ( unsigned i = 0; i < _ignoreFaceIds.size(); ++i ) + save << " " << _ignoreFaceIds[i]; + return save; +} // -------------------------------------------------------------------------------- +std::istream & StdMeshers_ViscousLayers::LoadFrom(std::istream & load) +{ + int nbFaces, faceID; + load >> _nbLayers >> _thickness >> _stretchFactor >> nbFaces; + while ( _ignoreFaceIds.size() < nbFaces && load >> faceID ) + _ignoreFaceIds.push_back( faceID ); + return load; +} // -------------------------------------------------------------------------------- +bool StdMeshers_ViscousLayers::SetParametersByMesh(const SMESH_Mesh* theMesh, + const TopoDS_Shape& theShape) +{ + // TODO + return false; +} +// END StdMeshers_ViscousLayers hypothesis +//================================================================================ + +namespace +{ + gp_XYZ getEdgeDir( const TopoDS_Edge& E, const TopoDS_Vertex& fromV ) + { + gp_Vec dir; + double f,l; + Handle(Geom_Curve) c = BRep_Tool::Curve( E, f, l ); + gp_Pnt p = BRep_Tool::Pnt( fromV ); + double distF = p.SquareDistance( c->Value( f )); + double distL = p.SquareDistance( c->Value( l )); + c->D1(( distF < distL ? f : l), p, dir ); + if ( distL < distF ) dir.Reverse(); + return dir.XYZ(); + } + //-------------------------------------------------------------------------------- + // DEBUG. Dump intermediate nodes positions into a python script + //#define __PY_DUMP +#ifdef __PY_DUMP + ofstream* py; + void initPyDump() + { + const char* fname = "/tmp/viscous.py"; + cout << "execfile('"<GetID()<< ", "<< n->X()<< ", "<Y()<<", "<< n->Z()<< ") "<myName = COMPERR_ALGO_FAILED; + _error->myComment = text; + if ( _mesh ) + { + if ( !data && !_sdVec.empty() ) + data = & _sdVec[0]; + if ( data ) + { + SMESH_subMesh* sm = _mesh->GetSubMesh( data->_solid ); + SMESH_ComputeErrorPtr& smError = sm->GetComputeError(); + if ( smError && smError->myAlgo ) + _error->myAlgo = smError->myAlgo; + smError = _error; + } + } + return false; +} + +//================================================================================ +/*! + * \brief Does its job + */ +//================================================================================ + +SMESH_ComputeErrorPtr _ViscousBuilder::Compute(SMESH_Mesh& theMesh, + const TopoDS_Shape& theShape) +{ +#ifdef __PY_DUMP + initPyDump(); +#endif + // TODO: set priority of solids during Gen::Compute() + + _mesh = & theMesh; + + // check if proxy mesh already computed + TopExp_Explorer exp( theShape, TopAbs_SOLID ); + if ( !exp.More() ) + return error("No SOLID's in theShape", 0), _error; + + if ( _ViscousListener::GetSolidMesh( _mesh, exp.Current(), /*toCreate=*/false)) + return SMESH_ComputeErrorPtr(); // everything already computed + + + findSolidsWithLayers(); + if ( _error->IsOK() ) + findFacesWithLayers(); + + for ( unsigned i = 0; i < _sdVec.size(); ++i ) + { + if ( ! makeLayer(_sdVec[i]) ) + break; + + if ( ! inflate(_sdVec[i]) ) { + makeGroupOfLE(); + break; + } + if ( ! refine(_sdVec[i]) ) + break; + } + if ( _error->IsOK() ) + shrink(); + +#ifdef __PY_DUMP + delete py; py = 0; +#endif + return _error; +} + +//================================================================================ +/*! + * \brief Finds SOLIDs to compute using viscous layers. Fill _sdVec + */ +//================================================================================ + +bool _ViscousBuilder::findSolidsWithLayers() +{ + // get all solids + TopTools_IndexedMapOfShape allSolids; + TopExp::MapShapes( _mesh->GetShapeToMesh(), TopAbs_SOLID, allSolids ); + _sdVec.reserve( allSolids.Extent()); + + SMESH_Gen* gen = _mesh->GetGen(); + for ( int i = 1; i <= allSolids.Extent(); ++i ) + { + // find StdMeshers_ViscousLayers hyp assigned to the i-th solid + SMESH_Algo* algo = gen->GetAlgo( *_mesh, allSolids(i) ); + if ( !algo ) continue; + // TODO: check if algo is hidden + const list & allHyps = + algo->GetUsedHypothesis(*_mesh, allSolids(i), /*ignoreAuxiliary=*/false); + list< const SMESHDS_Hypothesis *>::const_iterator hyp = allHyps.begin(); + const StdMeshers_ViscousLayers* viscHyp = 0; + for ( ; hyp != allHyps.end() && !viscHyp; ++hyp ) + viscHyp = dynamic_cast( *hyp ); + if ( viscHyp ) + { + _MeshOfSolid* proxyMesh = _ViscousListener::GetSolidMesh( _mesh, + allSolids(i), + /*toCreate=*/true); + _sdVec.push_back( _SolidData( allSolids(i), viscHyp, proxyMesh )); + _sdVec.back()._index = _sdVec.size()-1; // debug + } + } + if ( _sdVec.empty() ) + return error + ( SMESH_Comment(StdMeshers_ViscousLayers::GetHypType()) << " hypothesis not found",0); + + return true; +} + +//================================================================================ +/*! + * \brief + */ +//================================================================================ + +bool _ViscousBuilder::findFacesWithLayers() +{ + // collect all faces to ignore defined by hyp + vector ignoreFaces; + for ( unsigned i = 0; i < _sdVec.size(); ++i ) + { + vector ids = _sdVec[i]._hyp->GetIgnoreFaces(); + for ( unsigned i = 0; i < ids.size(); ++i ) + { + const TopoDS_Shape& s = getMeshDS()->IndexToShape( ids[i] ); + if ( !s.IsNull() && s.ShapeType() == TopAbs_FACE ) + { + _ignoreShapeIds.insert( ids[i] ); + ignoreFaces.push_back( s ); + } + } + } + + // ignore internal faces + SMESH_MesherHelper helper( *_mesh ); + TopExp_Explorer exp; + for ( unsigned i = 0; i < _sdVec.size(); ++i ) + { + exp.Init( _sdVec[i]._solid.Oriented( TopAbs_FORWARD ), TopAbs_FACE ); + for ( ; exp.More(); exp.Next() ) + { + int faceInd = getMeshDS()->ShapeToIndex( exp.Current() ); + if ( helper.NbAncestors( exp.Current(), *_mesh, TopAbs_SOLID ) > 1 ) + { + _ignoreShapeIds.insert( faceInd ); + ignoreFaces.push_back( exp.Current() ); + if ( SMESH_Algo::IsReversedSubMesh( TopoDS::Face( exp.Current() ), getMeshDS())) + _sdVec[i]._reversedFaceIds.insert( faceInd ); + } + } + } + + // Find faces to shrink mesh on (solution 2 in issue 0020832); + // we use solution 1 for shared faces w/o layers since there is no generic way + // to know whether after shrinking 2D mesh remains valid for other 3D algo + TopTools_IndexedMapOfShape shapes; + for ( unsigned i = 0; i < _sdVec.size(); ++i ) + { + TopExp::MapShapes(_sdVec[i]._solid, TopAbs_EDGE, shapes); + for ( int iE = 1; iE <= shapes.Extent(); ++iE ) + { + const TopoDS_Shape& edge = shapes(iE); + // find 2 faces sharing an edge + TopoDS_Shape FF[2]; + PShapeIteratorPtr fIt = helper.GetAncestors(edge, *_mesh, TopAbs_FACE); + while ( fIt->more()) + { + const TopoDS_Shape* f = fIt->next(); + if ( helper.IsSubShape( *f, _sdVec[i]._solid)) + FF[ int( !FF[0].IsNull()) ] = *f; + } + ASSERT( !FF[1].IsNull() ); + // check presence of layers on them + int ignore[2]; + for ( int j = 0; j < 2; ++j ) + ignore[j] = _ignoreShapeIds.count ( getMeshDS()->ShapeToIndex( FF[j] )); + if ( ignore[0] == ignore[1] ) continue; // nothing interesting + // check if a face w/o layers (WOL) is shared + if ( !ignore[0] ) std::swap( FF[0], FF[1] ); // set face WOL to FF[0] +// bool shareWOL = ( helper.NbAncestors( FF[0], *_mesh, TopAbs_SOLID ) > 1 ); +// if ( shareWOL ) + { + // add edge to maps + int edgeInd = getMeshDS()->ShapeToIndex( edge ); + _sdVec[i]._shrinkShape2Shape.insert( make_pair( edgeInd, FF[0] )); + } + } + + // Find shapes along which to inflate _LayerEdge on vertex + + shapes.Clear(); + TopExp::MapShapes(_sdVec[i]._solid, TopAbs_VERTEX, shapes); + for ( int iV = 1; iV <= shapes.Extent(); ++iV ) + { + const TopoDS_Shape& vertex = shapes(iV); + // find faces WOL sharing the vertex + vector< TopoDS_Shape > faces; + int totalNbFaces = 0; + PShapeIteratorPtr fIt = helper.GetAncestors(vertex, *_mesh, TopAbs_FACE); + while ( fIt->more()) + { + const TopoDS_Shape* f = fIt->next(); + totalNbFaces++; + if ( helper.IsSubShape( *f, _sdVec[i]._solid) && + _ignoreShapeIds.count ( getMeshDS()->ShapeToIndex( *f ))) + faces.push_back( *f ); + } + if ( faces.size() == totalNbFaces || faces.empty() ) + continue; // not layers at this vertex or no WOL + int vInd = getMeshDS()->ShapeToIndex( vertex ); + switch ( faces.size() ) + { + case 1: + { + _sdVec[i]._shrinkShape2Shape.insert( make_pair( vInd, faces[0] )); break; + } + case 2: + { + // find an edge shared by 2 faces + PShapeIteratorPtr eIt = helper.GetAncestors(vertex, *_mesh, TopAbs_EDGE); + while ( eIt->more()) + { + const TopoDS_Shape* e = eIt->next(); + if ( helper.IsSubShape( *e, faces[0]) && + helper.IsSubShape( *e, faces[1]) && + helper.IsSubShape( vertex, *e )) + { + _sdVec[i]._shrinkShape2Shape.insert( make_pair( vInd, *e )); break; + } + } + break; + } + default: + return error("Not yet supported case", &_sdVec[i]); + } + } + } + // TODO: treat cases with solution 1. + + return true; +} + +//================================================================================ +/*! + * \brief Create the inner surface of the viscous layer and prepare data for infation + */ +//================================================================================ + +bool _ViscousBuilder::makeLayer(_SolidData& data) +{ + // get all sub-shapes to make layers on + set subIds, faceIds; + set::iterator id; + TopExp_Explorer exp( data._solid, TopAbs_FACE ); + for ( ; exp.More(); exp.Next() ) + if ( ! _ignoreShapeIds.count( getMeshDS()->ShapeToIndex( exp.Current() ))) + { + SMESH_subMesh* fSubM = _mesh->GetSubMesh( exp.Current() ); + faceIds.insert( fSubM->GetId() ); + SMESH_subMeshIteratorPtr subIt = + fSubM->getDependsOnIterator(/*includeSelf=*/true, /*complexShapeFirst=*/false); + while ( subIt->more() ) + subIds.insert( subIt->next()->GetId() ); + } + + // make a map to find new nodes on sub-shapes shared with other solid + map< int, TNode2Edge* > s2neMap; + map< int, TNode2Edge* >::iterator s2ne; + map< int, TopoDS_Shape >::iterator s2s = data._shrinkShape2Shape.begin(); + for (; s2s != data._shrinkShape2Shape.end(); ++s2s ) + { + int shapeInd = s2s->first; + for ( unsigned i = 0; i < _sdVec.size(); ++i ) + { + map< int, TopoDS_Shape >::iterator s2s2 = _sdVec[i]._shrinkShape2Shape.find( shapeInd ); + if ( *s2s == *s2s2 && !_sdVec[i]._n2eMap.empty() ) + { + s2neMap.insert( make_pair( shapeInd, &_sdVec[i]._n2eMap )); + break; + } + } + } + + // Create temporary faces and _LayerEdge's + + data._stepSize = numeric_limits::max(); + + SMESH_MesherHelper helper( *_mesh ); + helper.SetSubShape( data._solid ); + helper.SetElementsOnShape(true); + + vector< const SMDS_MeshNode*> newNodes; + TNode2Edge::iterator n2e2; + + // collect all _LayerEdge's to inflate along a FACE + TopTools_IndexedMapOfShape srinkFaces; // to index only srinkFaces + map< int, vector<_LayerEdge*> > srinkFace2edges; + + for ( set::iterator id = faceIds.begin(); id != faceIds.end(); ++id ) + { + SMESHDS_SubMesh* smDS = getMeshDS()->MeshElements( *id ); + if ( !smDS ) return error(SMESH_Comment("Not meshed face ") << *id, &data ); + + const TopoDS_Face& F = TopoDS::Face( getMeshDS()->IndexToShape( *id )); + StdMeshers_ProxyMesh::SubMesh* proxySub = + data._proxyMesh->getFaceData( F, /*create=*/true); + + SMDS_ElemIteratorPtr eIt = smDS->GetElements(); + while ( eIt->more() ) + { + const SMDS_MeshElement* face = eIt->next(); + newNodes.resize( face->NbCornerNodes() ); + double faceMaxCosin = -1; + for ( int i = 0 ; i < face->NbCornerNodes(); ++i ) + { + const SMDS_MeshNode* n = face->GetNode(i); + TNode2Edge::iterator n2e = data._n2eMap.insert( make_pair( n, (_LayerEdge*)0 )).first; + if ( !(*n2e).second ) + { + // add a _LayerEdge + _LayerEdge* edge = new _LayerEdge(); + n2e->second = edge; + edge->_nodes.push_back( n ); + + // set edge data or find already refined _LayerEdge and get data from it + if ( n->GetPosition()->GetTypeOfPosition() != SMDS_TOP_FACE && + ( s2ne = s2neMap.find( n->GetPosition()->GetShapeId() )) != s2neMap.end() && + ( n2e2 = (*s2ne).second->find( n )) != s2ne->second->end()) + { + _LayerEdge* foundEdge = (*n2e2).second; + edge->_nodes = foundEdge->_nodes; + edge->_normal = foundEdge->_normal; + edge->_len = 0; + edge->_cosin = foundEdge->_cosin; + edge->_sWOL = foundEdge->_sWOL; + // location of the last node is modified but we can restore + // it by node position on _sWOL stored by the node + const_cast< SMDS_MeshNode* > + ( edge->_nodes.back() )->setXYZ( n->X(), n->Y(), n->Z() ); + } + else + { + edge->_nodes.push_back( helper.AddNode( n->X(), n->Y(), n->Z() )); + if ( !setEdgeData( *edge, subIds, helper, data )) + return false; + } + if ( edge->_cosin <= 1. ) + { + if ( edge->_cosin > faceMaxCosin ) + faceMaxCosin = edge->_cosin; + } + if ( edge->IsOnEdge() ) + { + // _LayerEdge is based on EDGE + int faceId = srinkFaces.Add( edge->_sWOL ); + srinkFace2edges[ faceId ].push_back( edge ); + } + } + newNodes[ i ] = n2e->second->_nodes.back(); + } + // create a temporary face + const SMDS_MeshElement* newFace; + if ( newNodes.size() == 3 ) + newFace = new SMDS_FaceOfNodes( newNodes[0], newNodes[1], newNodes[2] ); + else + newFace = new SMDS_FaceOfNodes( newNodes[0], newNodes[1], newNodes[2], newNodes[3] ); + proxySub->AddElement( newFace ); + + // compute inflation step size by min size of element on a convex surface + if ( faceMaxCosin > 0.1 ) + { + double elemMinSize = numeric_limits::max(); + for ( unsigned i = 1; i < newNodes.size(); ++i ) + { + double len = SMESH_MeshEditor::TNodeXYZ( newNodes[i-1] ).Distance( newNodes[i] ); + if ( len < elemMinSize && len > numeric_limits::min() ) + elemMinSize = len; + } + double newStep = 0.8 * elemMinSize / faceMaxCosin; + if ( newStep < data._stepSize ) + data._stepSize = newStep; + } + } // loop on elements of a FACE + } // loop on FACEs of a SOLID + + // Put _LayerEdge's into a vector; + // first we put _LayerEdge's based on EDGES to smooth them before others + + data._edges.reserve( data._n2eMap.size() ); + map< int, vector<_LayerEdge*> >::iterator fi2e = srinkFace2edges.begin(); + for ( ; fi2e != srinkFace2edges.end(); ++fi2e ) + { + const TopoDS_Face& F = TopoDS::Face( srinkFaces( fi2e->first )); + vector<_LayerEdge*> eVec = fi2e->second; + data._edges.insert( data._edges.end(), eVec.begin(), eVec.end() ); + data._endEdge2Face[ data._edges.size() ] = F; + } + TNode2Edge::iterator n2e = data._n2eMap.begin(); + for ( ; n2e != data._n2eMap.end(); ++n2e ) + { + _LayerEdge* e = n2e->second; + if ( !e->IsOnEdge() ) + data._edges.push_back( e ); + } + + // Set new nodes into simplices + //int i0 = data._endEdge2Face.empty() ? 0 : data._endEdge2Face.rbegin()->first; + for ( unsigned i = 0; i < data._edges.size(); ++i ) + { + //if ( !data._edges[i]->_sWOL.IsNull() ) continue; + for ( unsigned j = 0; j < data._edges[i]->_simplices.size(); ++j ) + { + _Simplex& s = data._edges[i]->_simplices[j]; + s._nPrev = data._n2eMap[ s._nPrev ]->_nodes.back(); + s._nNext = data._n2eMap[ s._nNext ]->_nodes.back(); + } + } + return true; +} + +//================================================================================ +/*! + * \brief Set data of _LayerEdge needed for smoothing + * \param subIds - ids of sub-shapes of a SOLID to take into account faces from + */ +//================================================================================ + +bool _ViscousBuilder::setEdgeData(_LayerEdge& edge, + const set& subIds, + SMESH_MesherHelper& helper, + _SolidData& data) +{ + SMESH_MeshEditor editor(_mesh); + + const SMDS_MeshNode* node = edge._nodes[0]; + + edge._len = 0; + + // --------------------- + // Compute edge._normal + // --------------------- + + edge._normal.SetCoord(0,0,0); + + gp_Pnt p; + gp_Vec du, dv, geomNorm; + double f,l; + bool normOK = true; + + int shapeInd = node->GetPosition()->GetShapeId(); + map< int, TopoDS_Shape >::const_iterator s2s = data._shrinkShape2Shape.find( shapeInd ); + bool onShrinkShape ( s2s != data._shrinkShape2Shape.end() ); + TopoDS_Shape vertEdge; + + if ( onShrinkShape ) // one of faces the node is on has no layers + { + vertEdge = getMeshDS()->IndexToShape( s2s->first ); // vertex or edge + if ( s2s->second.ShapeType() == TopAbs_EDGE ) + { + // inflate from VERTEX along EDGE + edge._normal = getEdgeDir( TopoDS::Edge( s2s->second ), TopoDS::Vertex( vertEdge )); + } + else if ( vertEdge.ShapeType() == TopAbs_VERTEX ) + { + // inflate from VERTEX along FACE + vector< TopoDS_Shape > edges; // sharing a vertex + PShapeIteratorPtr eIt = helper.GetAncestors( vertEdge, *_mesh, TopAbs_EDGE); + while ( eIt->more()) + { + const TopoDS_Shape* e = eIt->next(); + if ( helper.IsSubShape( *e, s2s->second ) && + BRep_Tool::Curve( TopoDS::Edge( *e ), f, l)) + edges.push_back( *e ); + } + if ( edges.size() != 2 ) + return error("More that 2 edges share a vertex in face", &data); + for ( int i = 0; i < 2; ++i ) + { + gp_Vec edgeDir = getEdgeDir( TopoDS::Edge( edges[i] ), TopoDS::Vertex( vertEdge )); + double size2 = edgeDir.SquareMagnitude(); + if ( size2 > numeric_limits::min() ) + edgeDir /= sqrt( size2 ); + else + normOK = false; + edge._normal += edgeDir.XYZ() / 2; + } + } + else + { + // inflate from EDGE along FACE + gp_XY uv = helper.GetNodeUV( TopoDS::Face( s2s->second ), node, 0, &normOK ); + Handle(Geom_Surface) surface = BRep_Tool::Surface( TopoDS::Face( s2s->second )); + surface->D1( uv.X(),uv.Y(), p, du,dv ); + geomNorm = du ^ dv; + Handle(Geom_Curve) c = BRep_Tool::Curve( TopoDS::Edge( vertEdge), f, l ); + f = helper.GetNodeU( TopoDS::Edge( vertEdge ), node, 0, &normOK ); + c->D1( f, p, du ); + TopAbs_Orientation o = helper.GetSubShapeOri( s2s->second.Oriented(TopAbs_FORWARD),vertEdge); + if ( o == TopAbs_REVERSED ) + du.Reverse(); + edge._normal = (geomNorm ^ du ).XYZ(); + } + } + else // layers are on all faces of SOLID the node is on + { + // find indices of geom faces the node lies on + set faceIds; + if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE ) + { + faceIds.insert( node->GetPosition()->GetShapeId() ); + } + else + { + SMDS_ElemIteratorPtr fIt = node->GetInverseElementIterator(SMDSAbs_Face); + while ( fIt->more() ) + faceIds.insert( editor.FindShape(fIt->next())); + } + + set::iterator id = faceIds.begin(); + int totalNbFaces = 0/*, nbLayerFaces = 0*/; + for ( ; id != faceIds.end(); ++id ) + { + const TopoDS_Shape& s = getMeshDS()->IndexToShape( *id ); + if ( s.IsNull() || s.ShapeType() != TopAbs_FACE || !subIds.count( *id )) + continue; + totalNbFaces++; + //nbLayerFaces += subIds.count( *id ); + const TopoDS_Face& f = TopoDS::Face( s ); + + gp_XY uv = helper.GetNodeUV( f, node, 0, &normOK ); + Handle(Geom_Surface) surface = BRep_Tool::Surface( f ); + surface->D1( uv.X(),uv.Y(), p, du,dv ); + geomNorm = du ^ dv; + double size2 = geomNorm.SquareMagnitude(); + if ( size2 > numeric_limits::min() ) + geomNorm /= sqrt( size2 ); + else + normOK = false; + if ( helper.GetSubShapeOri( data._solid, f ) != TopAbs_REVERSED ) + geomNorm.Reverse(); + edge._normal += geomNorm.XYZ(); + } + if ( totalNbFaces == 0 ) + return error(SMESH_Comment("Can't get normal to node ") << node->GetID(), &data); + + edge._normal /= totalNbFaces; + } + + double normSize = edge._normal.SquareModulus(); + if ( normSize < numeric_limits::min() ) + return error(SMESH_Comment("Bad normal at node ")<< node->GetID(), &data ); + + edge._normal /= sqrt( normSize ); + + // TODO: if ( !normOK ) then get normal by mesh faces + + // Set the rest data + // -------------------- + if ( onShrinkShape ) + { + edge._cosin = 2; + edge._sWOL = (*s2s).second; + + // set initial position which is parameters on _sWOL in this case + SMDS_MeshNode* tgtNode = const_cast( edge._nodes.back() ); + if ( SMESHDS_SubMesh* sm = getMeshDS()->MeshElements( shapeInd )) + sm->RemoveNode( tgtNode , /*isNodeDeleted=*/false ); + if ( edge._sWOL.ShapeType() == TopAbs_EDGE ) + { + double u = helper.GetNodeU( TopoDS::Edge( edge._sWOL ), node, 0, &normOK ); + edge._pos.push_back( gp_XYZ( u, 0, 0)); + getMeshDS()->SetNodeOnEdge( tgtNode, TopoDS::Edge( edge._sWOL ), u ); + } + else // TopAbs_FACE + { + gp_XY uv = helper.GetNodeUV( TopoDS::Face( edge._sWOL ), node, 0, &normOK ); + edge._pos.push_back( gp_XYZ( uv.X(), uv.Y(), 0)); + getMeshDS()->SetNodeOnFace( tgtNode, TopoDS::Face( edge._sWOL ), uv.X(), uv.Y() ); + } + // set neighbour nodes for a _LayerEdge based on EDGE + if ( vertEdge.ShapeType() != TopAbs_VERTEX ) + { + edge._simplices.resize( 1 ); + _Simplex& neighborNodes = edge._simplices.back(); + SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Edge); + while ( eIt->more() && !neighborNodes._nNext ) + { + const SMDS_MeshElement* e = eIt->next(); + if ( !subIds.count( editor.FindShape(e))) + continue; + const SMDS_MeshNode* n2 = e->GetNode( 0 ); + if ( n2 == node ) n2 = e->GetNode( 1 ); + (neighborNodes._nPrev ? neighborNodes._nNext : neighborNodes._nPrev ) = n2; + } + } + } + else + { + double angle = ( du+dv ).Angle( edge._normal ); // [0,PI] + edge._cosin = cos( angle ); + + edge._pos.push_back( SMESH_MeshEditor::TNodeXYZ( node )); + + if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE ) + getSimplices( node, edge._simplices, _ignoreShapeIds, &data ); + } + return true; +} +//================================================================================ +/*! + * \brief Fills a vector<_Simplex > + */ +//================================================================================ + +void _ViscousBuilder::getSimplices( const SMDS_MeshNode* node, + vector<_Simplex>& simplices, + const set& ingnoreShapes, + const _SolidData* dataToCheckOri) +{ + SMESH_MeshEditor editor( _mesh ); + SMDS_ElemIteratorPtr fIt = node->GetInverseElementIterator(SMDSAbs_Face); + while ( fIt->more() ) + { + const SMDS_MeshElement* f = fIt->next(); + const int shapeInd = editor.FindShape( f ); + if ( ingnoreShapes.count( shapeInd )) continue; + const int nbNodes = f->NbCornerNodes(); + int srcInd = f->GetNodeIndex( node ); + const SMDS_MeshNode* nPrev = f->GetNode( SMESH_MesherHelper::WrapIndex( srcInd-1, nbNodes )); + const SMDS_MeshNode* nNext = f->GetNode( SMESH_MesherHelper::WrapIndex( srcInd+1, nbNodes )); + if ( dataToCheckOri && dataToCheckOri->_reversedFaceIds.count( shapeInd )) + std::swap( nPrev, nNext ); + simplices.push_back( _Simplex( nPrev, nNext )); + } + simplices.resize( simplices.size() ); +} + +//================================================================================ +/*! + * \brief DEBUG. Create groups of edges contating segments of _LayerEdge's + */ +//================================================================================ + +void _ViscousBuilder::makeGroupOfLE() +{ +#ifdef _DEBUG_ + for ( unsigned i = 0 ; i < _sdVec.size(); ++i ) + { + if ( _sdVec[i]._edges.empty() ) continue; + string name = SMESH_Comment("_LayerEdge's_") << i; + int id; + SMESH_Group* g = _mesh->AddGroup(SMDSAbs_Edge, name.c_str(), id ); + SMESHDS_Group* gDS = (SMESHDS_Group*)g->GetGroupDS(); + SMESHDS_Mesh* mDS = _mesh->GetMeshDS(); + + for ( unsigned j = 0 ; j < _sdVec[i]._edges.size(); ++j ) + { + _LayerEdge* le = _sdVec[i]._edges[j]; + for ( unsigned iN = 1; iN < le->_nodes.size(); ++iN ) + gDS->SMDSGroup().Add( mDS->AddEdge( le->_nodes[iN-1], le->_nodes[iN])); + } + + name = SMESH_Comment("Normals_") << i; + g = _mesh->AddGroup(SMDSAbs_Edge, name.c_str(), id ); + gDS = (SMESHDS_Group*)g->GetGroupDS(); + SMESH_MesherHelper helper( *_mesh ); + for ( unsigned j = 0 ; j < _sdVec[i]._edges.size(); ++j ) + { + _LayerEdge leCopy = *_sdVec[i]._edges[j]; + leCopy._len = 0; + SMESH_MeshEditor::TNodeXYZ nXYZ( leCopy._nodes[0] ); + SMDS_MeshNode* n = const_cast< SMDS_MeshNode*>( leCopy._nodes.back() ); + n->setXYZ( nXYZ.X(), nXYZ.Y(), nXYZ.Z() ); + leCopy.SetNewLength( _sdVec[i]._stepSize, helper ); + gDS->SMDSGroup().Add( mDS->AddEdge( leCopy._nodes[0], n )); + } + } +#endif +} + +//================================================================================ +/*! + * \brief Increase length of _LayerEdge's to reach the required thickness of layers + */ +//================================================================================ + +bool _ViscousBuilder::inflate(_SolidData& data) +{ + SMESH_MesherHelper helper( *_mesh ); + + double tgtThick = data._hyp->GetTotalThickness(); + if ( data._stepSize > tgtThick ) + data._stepSize = tgtThick; + double avgThick = 0, curThick = 0; + int nbSteps = 0, nbRepeats = 0; + while ( 1.01 * avgThick < tgtThick ) + { + dumpFunction(SMESH_Comment("inflate")< tgtThick ) + { + curThick = tgtThick + ( tgtThick-avgThick ) * nbRepeats; + nbRepeats++; + } + // elongate _LayerEdge's + for ( unsigned i = 0; i < data._edges.size(); ++i ) + data._edges[i]->SetNewLength( curThick, helper ); + + dumpFunctionEnd(); + + // improve aand check quality + if ( !smoothAndCheck( data )) + { + if ( nbSteps == 0 ) + return error("Viscous builder failed at the very first inflation step", &data); + + for ( unsigned i = 0; i < data._edges.size(); ++i ) + data._edges[i]->InvalidateStep( nbSteps+1 ); + + break; // no more inflating possible + } + // evaluate achieved thickness + avgThick = 0; + for ( unsigned i = 0; i < data._edges.size(); ++i ) + avgThick += data._edges[i]->_len; + avgThick /= data._edges.size(); + + nbSteps++; + } + return true; +} + +//================================================================================ +/*! + * \brief Improve quality of layer inner surface and check intersection + */ +//================================================================================ + +bool _ViscousBuilder::smoothAndCheck(_SolidData& data) +{ + // Smoothing + + bool moved = true, improved = true; + int iOnEdgeEnd = data._endEdge2Face.empty() ? 0 : data._endEdge2Face.rbegin()->first; + if ( !data._endEdge2Face.empty() ) + { + // first we smooth _LayerEdge's based on EDGES + SMESH_MesherHelper helper(*_mesh); + int iBeg = 0; + map< int, TopoDS_Face >::iterator nb2f = data._endEdge2Face.begin(); + for ( ; nb2f != data._endEdge2Face.end(); ++nb2f ) + { + Handle(Geom_Surface) surface = BRep_Tool::Surface( nb2f->second ); + helper.SetSubShape( nb2f->second ); + int nb = nb2f->first, step = 0; + do { + dumpFunction(SMESH_Comment("smooth")<Smooth2d(surface, helper); + + dumpFunctionEnd(); + } + while ( moved ); + + iBeg = nb; + + } + } + // smooth in 3D + int step = 0, badNb = 0; moved = true; + while (( ++step <= 5 && moved ) || improved ) + { + dumpFunction(SMESH_Comment("smooth")<Smooth(badNb) || moved; + improved = ( badNb < oldBadNb ); + + dumpFunctionEnd(); + } + if ( badNb > 0 ) + return false; + + // Check if the last segments of _LayerEdge intersects 2D elements, + // checked elements are either temporary faces or faces on surfaces w/o the layers + + SMESH_MeshEditor editor( _mesh ); + SMESH_ElementSearcher* searcher = + editor.GetElementSearcher( data._proxyMesh->GetFaces( data._solid )); + + vector< const SMDS_MeshElement* > suspectFaces; + for ( unsigned i = 0; i < data._edges.size(); ++i ) + { + const _LayerEdge& edge = * data._edges[i]; + gp_Ax1 lastSegment = edge.LastSegment(); + searcher->GetElementsNearLine( lastSegment, SMDSAbs_Face, suspectFaces ); + + for ( unsigned j = 0 ; j < suspectFaces.size(); ++j ) + { + const SMDS_MeshElement* face = suspectFaces[j]; + if ( face->GetNodeIndex( edge._nodes.back() ) >= 0 ) + continue; // face sharing _LayerEdge node + const int nbNodes = face->NbCornerNodes(); + bool intFound = false; + if ( nbNodes == 3 ) + { + SMDS_MeshElement::iterator nIt = face->begin_nodes(); + intFound = edge.SegTriaInter( lastSegment, *nIt++, *nIt++, *nIt++ ); + } + else + { + const SMDS_MeshNode* tria[3]; + tria[0] = face->GetNode(0); + tria[1] = face->GetNode(1); + for ( int n2 = 2; n2 < nbNodes && !intFound; ++n2 ) + { + tria[2] = face->GetNode(n2); + intFound = edge.SegTriaInter(lastSegment, tria[0], tria[1], tria[2] ); + tria[1] = tria[2]; + } + } + if ( intFound ) + return false; + } + } + return true; +} + +//================================================================================ +/*! + * \brief Returns direction of the last segment + */ +//================================================================================ + +gp_Ax1 _LayerEdge::LastSegment() const +{ + // find two non-coincident positions + gp_XYZ orig = _pos.back(); + gp_XYZ dir; + int iPrev = _pos.size() - 2; + while ( iPrev > 0 ) + { + dir = orig - _pos[iPrev--]; + if ( dir.SquareModulus() > 1e-100 ) + break; + } + + // make gp_Ax1 + gp_Ax1 segDir; + segDir.SetLocation( SMESH_MeshEditor::TNodeXYZ( _nodes.back() )); + if ( iPrev < 1 ) + { + segDir.SetDirection( _normal ); + } + else + { + if ( !_sWOL.IsNull() ) + { + gp_Pnt pPrev; + const gp_XYZ& par = _pos[ iPrev ]; + TopLoc_Location loc; + if ( _sWOL.ShapeType() == TopAbs_EDGE ) + { + double f,l; + Handle(Geom_Curve) curve = BRep_Tool::Curve( TopoDS::Edge( _sWOL ), loc, f,l); + pPrev = curve->Value( par.X() ).Transformed( loc ); + } + else + { + Handle(Geom_Surface) surface = BRep_Tool::Surface( TopoDS::Face(_sWOL), loc ); + pPrev = surface->Value( par.X(), par.Y() ).Transformed( loc ); + } + dir = segDir.Location().XYZ() - pPrev.XYZ(); + } + segDir.SetDirection( dir ); + } + return segDir; +} + +//================================================================================ +/*! + * \brief Perform smooth in 2D space of a face + * \retval bool - true if node has been moved + */ +//================================================================================ + +bool _LayerEdge::Smooth2d(Handle(Geom_Surface)& surface, SMESH_MesherHelper& helper) +{ + // smooth _LayerEdge based on EDGE and inflated along FACE + + const TopoDS_Face& face = TopoDS::Face( _sWOL ); + + SMDS_MeshNode* tgtNode = const_cast( _nodes.back() ); + gp_XYZ& uv0 = _pos.back(); + + gp_XY uv1 = helper.GetNodeUV( face, _simplices[0]._nPrev, tgtNode ); + gp_XY uv2 = helper.GetNodeUV( face, _simplices[0]._nNext, tgtNode ); + gp_XY uvNew = 0.5 * (uv1 + uv2); + + double dist12 = (uv1 - uv2).Modulus(); + double distNewOld = (uvNew - gp_XY( uv0.X(), uv0.Y() )).Modulus(); + + SMDS_FacePosition* pos = static_cast( tgtNode->GetPosition().get() ); + pos->SetUParameter( uvNew.X() ); + pos->SetVParameter( uvNew.Y() ); + uv0.SetCoord( uvNew.X(), uvNew.Y(), 0 ); + + bool moved = distNewOld > dist12/50; + if ( moved ) + { + gp_Pnt p = surface->Value( uvNew.X(), uvNew.Y() ); + tgtNode->setXYZ( p.X(), p.Y(), p.Z() ); + dumpMove( tgtNode ); // debug + } + return moved; +} + +//================================================================================ +/*! + * \brief Perform laplacian smooth of nodes inflated from FACE + * \retval bool - true if _tgtNode has been moved + */ +//================================================================================ + +bool _LayerEdge::Smooth(int& badNb) +{ + if ( _simplices.size() < 2 ) + return false; // _LayerEdge inflated along EDGE or FACE + + // compute new position for the last _pos + gp_XYZ newPos (0,0,0); + for ( unsigned i = 0; i < _simplices.size(); ++i ) + newPos += SMESH_MeshEditor::TNodeXYZ( _simplices[i]._nPrev ); + newPos /= _simplices.size(); + + gp_Pnt prevPos( _pos[ _pos.size()-2 ]); + if ( _cosin < -0.1) + { + // Avoid decreasing length of edge on concave surface + //gp_Vec oldMove( _pos[ _pos.size()-2 ], _pos.back() ); + gp_Vec newMove( prevPos, newPos ); + newPos = _pos.back() + newMove.XYZ(); + } + else if ( _cosin > 0.3 ) + { + // Avoid increasing length of edge too much + + } + // count quality metrics (orientation) of tetras around _tgtNode + int nbOkBefore = 0; + SMESH_MeshEditor::TNodeXYZ tgtXYZ( _nodes.back() ); + for ( unsigned i = 0; i < _simplices.size(); ++i ) + nbOkBefore += _simplices[i].IsForward( _nodes[0], &tgtXYZ ); + + int nbOkAfter = 0; + for ( unsigned i = 0; i < _simplices.size(); ++i ) + nbOkAfter += _simplices[i].IsForward( _nodes[0], &newPos ); + + if ( nbOkAfter < nbOkBefore ) + return false; + + SMDS_MeshNode* n = const_cast< SMDS_MeshNode* >( _nodes.back() ); + + _len -= prevPos.Distance(SMESH_MeshEditor::TNodeXYZ( n )); + _len += prevPos.Distance(newPos); + + n->setXYZ( newPos.X(), newPos.Y(), newPos.Z()); + _pos.back() = newPos; + + badNb += _simplices.size() - nbOkAfter; + + dumpMove( n ); + + return true; +} + +//================================================================================ +/*! + * \brief Test intersection of the last segment with a given triangle + * using Moller-Trumbore algorithm + */ +//================================================================================ + +bool _LayerEdge::SegTriaInter( const gp_Ax1& lastSegment, + const SMDS_MeshNode* n0, + const SMDS_MeshNode* n1, + const SMDS_MeshNode* n2 ) const +{ + const double EPSILON = 1e-6; + + gp_XYZ orig = lastSegment.Location().XYZ(); + gp_XYZ dir = lastSegment.Direction().XYZ(); + + SMESH_MeshEditor::TNodeXYZ vert0( n0 ); + SMESH_MeshEditor::TNodeXYZ vert1( n1 ); + SMESH_MeshEditor::TNodeXYZ vert2( n2 ); + + gp_XYZ edge1 = vert1 - vert0; + gp_XYZ edge2 = vert2 - vert0; + + /* begin calculating determinant - also used to calculate U parameter */ + gp_XYZ pvec = dir ^ edge2; + + /* if determinant is near zero, ray lies in plane of triangle */ + double det = edge1 * pvec; + + if (det < EPSILON) + return false; + + /* calculate distance from vert0 to ray origin */ + gp_XYZ tvec = orig - vert0; + + /* calculate U parameter and test bounds */ + double u = tvec * pvec; + if (u < 0.0 || u > det) + return 0; + + /* prepare to test V parameter */ + gp_XYZ qvec = tvec ^ edge1; + + /* calculate V parameter and test bounds */ + double v = dir * qvec; + if (v < 0.0 || u + v > det) + return 0; + + /* calculate t, scale parameters, ray intersects triangle */ + double t = edge2 * qvec; + double inv_det = 1.0 / det; + t *= inv_det; + //u *= inv_det; + //v *= inv_det; + + bool intersection = t < _len; + if ( intersection ) + { + gp_XYZ intP( orig + dir * t ); + cout << "src node " << _nodes.back()->GetID() << ", intersection with face " + << n0->GetID() << " " << n1->GetID() << " " << n2->GetID() << endl + << " at point " << intP.X() << ", " << intP.Y() << ", " << intP.Z() << endl; + } + return intersection; +} + +//================================================================================ +/*! + * \brief Add a new segment to _LayerEdge + */ +//================================================================================ + +void _LayerEdge::SetNewLength( double len, SMESH_MesherHelper& helper ) +{ + if ( _len - len > -1e-6 ) + { + _pos.push_back( _pos.back() ); + return; + } + SMDS_MeshNode* n = const_cast< SMDS_MeshNode*>( _nodes.back() ); + SMESH_MeshEditor::TNodeXYZ oldXYZ( n ); + gp_XYZ nXYZ = oldXYZ + _normal * ( len - _len ); + n->setXYZ( nXYZ.X(), nXYZ.Y(), nXYZ.Z() ); + + _pos.push_back( nXYZ ); + if ( _sWOL.IsNull() ) + { + _len = len; + } + else + { + double distXYZ[4]; + if ( _sWOL.ShapeType() == TopAbs_EDGE ) + { + double u = Precision::Infinite(); // to force projection w/o distance check + helper.CheckNodeU( TopoDS::Edge( _sWOL ), n, u, 1e-10, /*force=*/true, distXYZ ); + _pos.back().SetCoord( u, 0, 0 ); + SMDS_EdgePosition* pos = static_cast( n->GetPosition().get() ); + pos->SetUParameter( u ); + } + else // TopAbs_FACE + { + gp_XY uv( Precision::Infinite(), 0 ); + helper.CheckNodeUV( TopoDS::Face( _sWOL ), n, uv, 1e-10, /*force=*/true, distXYZ ); + _pos.back().SetCoord( uv.X(), uv.Y(), 0 ); + SMDS_FacePosition* pos = static_cast( n->GetPosition().get() ); + pos->SetUParameter( uv.X() ); + pos->SetVParameter( uv.Y() ); + } + n->setXYZ( distXYZ[1], distXYZ[2], distXYZ[3]); + _len += oldXYZ.Distance( n ); + } + dumpMove( n ); //debug +} + +//================================================================================ +/*! + * \brief Remove last inflation step + */ +//================================================================================ + +void _LayerEdge::InvalidateStep( int curStep ) +{ + if ( _pos.size() > curStep+1 ) + { + _pos.resize( curStep+1 ); + gp_Pnt nXYZ = _pos.back(); + SMDS_MeshNode* n = const_cast< SMDS_MeshNode*>( _nodes.back() ); + if ( !_sWOL.IsNull() ) + { + TopLoc_Location loc; + if ( _sWOL.ShapeType() == TopAbs_EDGE ) + { + double f,l; + Handle(Geom_Curve) curve = BRep_Tool::Curve( TopoDS::Edge( _sWOL ), loc, f,l); + nXYZ = curve->Value( nXYZ.X() ).Transformed( loc ); + } + else + { + Handle(Geom_Surface) surface = BRep_Tool::Surface( TopoDS::Face(_sWOL), loc ); + nXYZ = surface->Value( nXYZ.X(), nXYZ.Y() ).Transformed( loc ); + } + } + n->setXYZ( nXYZ.X(), nXYZ.Y(), nXYZ.Z() ); + } +} + +//================================================================================ +/*! + * \brief Create layers of prisms + */ +//================================================================================ + +bool _ViscousBuilder::refine(_SolidData& data) +{ + SMESH_MesherHelper helper( *_mesh ); + helper.SetSubShape( data._solid ); + + Handle(Geom_Curve) curve; + Handle(Geom_Surface) surface; + TopoDS_Edge geomEdge; + TopoDS_Face geomFace; + TopLoc_Location loc; + double f,l, u/*, distXYZ[4]*/; + gp_XY uv; + bool isOnEdge; + + for ( unsigned i = 0; i < data._edges.size(); ++i ) + { + _LayerEdge& edge = *data._edges[i]; + + helper.SetElementsOnShape(edge._sWOL.IsNull()); + + // get accumulated length of segments + vector< double > segLen( edge._pos.size() ); + segLen[0] = 0.0; + for ( unsigned j = 1; j < edge._pos.size(); ++j ) + segLen[j] = segLen[j-1] + (edge._pos[j-1] - edge._pos[j] ).Modulus(); + + // allocate memory for new nodes if it is not yet refined + const SMDS_MeshNode* tgtNode = edge._nodes.back(); + if ( edge._nodes.size() == 2 ) + { + edge._nodes.resize( data._hyp->GetNumberLayers() + 1, 0 ); + edge._nodes[1] = 0; + edge._nodes.back() = tgtNode; + } + if ( !edge._sWOL.IsNull() ) + { + isOnEdge = ( edge._sWOL.ShapeType() == TopAbs_EDGE ); + // restore position of the last node +// gp_Pnt p; + if ( isOnEdge ) + { + geomEdge = TopoDS::Edge( edge._sWOL ); + curve = BRep_Tool::Curve( geomEdge, loc, f,l); +// double u = helper.GetNodeU( tgtNode ); +// p = curve->Value( u ); + } + else + { + geomFace = TopoDS::Face( edge._sWOL ); + surface = BRep_Tool::Surface( geomFace, loc ); +// gp_XY uv = helper.GetNodeUV( tgtNode ); +// p = surface->Value( uv.X(), uv.Y() ); + } +// p.Transform( loc ); +// const_cast< SMDS_MeshNode* >( tgtNode )->setXYZ( p.X(), p.Y(), p.Z() ); + } + // calculate height of the first layer + const double T = segLen.back(); //data._hyp.GetTotalThickness(); + const double f = data._hyp->GetStretchFactor(); + const int N = data._hyp->GetNumberLayers(); + double h0 = T * ( f - 1 )/( pow( f, N ) - 1 ); + + const double zeroLen = std::numeric_limits::min(); + + // create intermediate nodes + double hSum = 0, hi = h0/f; + unsigned iSeg = 1; + for ( unsigned iStep = 1; iStep < edge._nodes.size(); ++iStep ) + { + hi *= f; + hSum += hi; + while ( hSum > segLen[iSeg] && iSeg < segLen.size()-1) + ++iSeg; + int iPrevSeg = iSeg-1; + while ( fabs( segLen[iPrevSeg] - segLen[iSeg]) <= zeroLen && iPrevSeg > 0 ) + --iPrevSeg; + double r = ( segLen[iSeg] - hSum ) / ( segLen[iSeg] - segLen[iPrevSeg] ); + gp_Pnt pos = r * edge._pos[iPrevSeg] + (1-r) * edge._pos[iSeg]; + SMDS_MeshNode*& node = const_cast< SMDS_MeshNode*& >(edge._nodes[ iStep ]); + if ( !edge._sWOL.IsNull() ) + { + // compute XYZ by parameters + if ( isOnEdge ) + { + u = pos.X(); + pos = curve->Value( u ).Transformed(loc); + } + else + { + uv.SetCoord( pos.X(), pos.Y() ); + pos = surface->Value( pos.X(), pos.Y() ).Transformed(loc); + } + } + if ( !node ) + { + node = helper.AddNode( pos.X(), pos.Y(), pos.Z()); + if ( !edge._sWOL.IsNull() ) + { + if ( isOnEdge ) + getMeshDS()->SetNodeOnEdge( node, geomEdge, u ); + else + getMeshDS()->SetNodeOnFace( node, geomFace, uv.X(), uv.Y() ); + } + } + else + { + if ( !edge._sWOL.IsNull() ) + { + // make average pos from new and current parameters + if ( isOnEdge ) + { + u = 0.5 * ( u + helper.GetNodeU( geomEdge, node )); + pos = curve->Value( u ); + } + else + { + uv = 0.5 * ( uv + helper.GetNodeUV( geomFace, node )); + pos = surface->Value( uv.X(), uv.Y()); + } + } + node->setXYZ( pos.X(), pos.Y(), pos.Z() ); + } + } + } + + // TODO: make quadratic prisms and polyhedrons(?) + + TopExp_Explorer exp( data._solid, TopAbs_FACE ); + for ( ; exp.More(); exp.Next() ) + { + if ( _ignoreShapeIds.count( getMeshDS()->ShapeToIndex( exp.Current() ))) + continue; + SMESHDS_SubMesh* fSubM = getMeshDS()->MeshElements( exp.Current() ); + SMDS_ElemIteratorPtr fIt = fSubM->GetElements(); + vector< vector* > nnVec; + while ( fIt->more() ) + { + const SMDS_MeshElement* face = fIt->next(); + int nbNodes = face->NbCornerNodes(); + nnVec.resize( nbNodes ); + SMDS_ElemIteratorPtr nIt = face->nodesIterator(); + for ( int iN = 0; iN < nbNodes; ++iN ) + { + const SMDS_MeshNode* n = static_cast( nIt->next() ); + nnVec[ iN ] = & data._n2eMap[ n ]->_nodes; + } + + int nbZ = nnVec[0]->size(); + switch ( nbNodes ) + { + case 3: + for ( int iZ = 1; iZ < nbZ; ++iZ ) + helper.AddVolume( (*nnVec[0])[iZ-1], (*nnVec[1])[iZ-1], (*nnVec[2])[iZ-1], + (*nnVec[0])[iZ], (*nnVec[1])[iZ], (*nnVec[2])[iZ]); + break; + case 4: + for ( int iZ = 1; iZ < nbZ; ++iZ ) + helper.AddVolume( (*nnVec[0])[iZ-1], (*nnVec[1])[iZ-1], + (*nnVec[2])[iZ-1], (*nnVec[3])[iZ-1], + (*nnVec[0])[iZ], (*nnVec[1])[iZ], + (*nnVec[2])[iZ], (*nnVec[3])[iZ]); + break; + default: + return error("Not supported type of element", &data); + } + } + } + return true; +} + +//================================================================================ +/*! + * \brief Shrink 2D mesh on faces to let space for inflated layers + */ +//================================================================================ + +bool _ViscousBuilder::shrink() +{ + // make map of (ids of faces to shrink mesh on) to (_SolidData containing _LayerEdge's + // inflated along face or edge) + map< int, _SolidData* > f2sdMap; + for ( unsigned i = 0 ; i < _sdVec.size(); ++i ) + { + _SolidData& data = _sdVec[i]; + map< int, TopoDS_Shape >::iterator s2s = data._shrinkShape2Shape.begin(); + for (; s2s != data._shrinkShape2Shape.end(); ++s2s ) + if ( s2s->second.ShapeType() == TopAbs_FACE ) + f2sdMap.insert( make_pair( getMeshDS()->ShapeToIndex( s2s->second ), &data )); + } + + SMESH_MesherHelper helper( *_mesh ); + + // loop on faces to srink mesh on + map< int, _SolidData* >::iterator f2sd = f2sdMap.begin(); + for ( ; f2sd != f2sdMap.end(); ++f2sd ) + { + _SolidData& data = *f2sd->second; + TNode2Edge& n2eMap = data._n2eMap; + const TopoDS_Face& F = TopoDS::Face( getMeshDS()->IndexToShape( f2sd->first )); + const bool reverse = ( data._reversedFaceIds.count( f2sd->first )); + + SMESH_subMesh* sm = _mesh->GetSubMesh( F ); + SMESHDS_SubMesh* smDS = sm->GetSubMeshDS(); + + helper.SetSubShape(F); + + // Create _SmoothNode's on face F + const set ignoreShapes; + vector< _SmoothNode > nodesToSmooth; + nodesToSmooth.reserve( smDS->NbElements() * 3 ); + { + int i = 0; + SMDS_NodeIteratorPtr nIt = smDS->GetNodes(); + while ( nIt->more() ) + { + const SMDS_MeshNode* n = nIt->next(); + nodesToSmooth.resize( i+1 ); + nodesToSmooth[ i ]._node = n; + getSimplices( n, nodesToSmooth[ i ]._simplices, ignoreShapes ); + if ( nodesToSmooth[ i ]._simplices.empty() ) + ;// n is created during refinement + else + ++i; + } + nodesToSmooth.resize( i ); + } + if ( nodesToSmooth.empty() ) continue; + + // Find out face orientation + double refSign = 1; + gp_XY uv = helper.GetNodeUV( F, nodesToSmooth[0]._node ); + if ( nodesToSmooth[0]._simplices[0].IsForward(uv, F, helper,refSign) != (!reverse)) + refSign = -1; + + // Find _LayerEdge's inflated along F + vector< _LayerEdge* > lEdges; + { + SMESH_subMeshIteratorPtr subIt = + sm->getDependsOnIterator(/*includeSelf=*/false, /*complexShapeFirst=*/false); + while ( subIt->more() ) + { + SMESH_subMesh* sub = subIt->next(); + SMESHDS_SubMesh* subDS = sub->GetSubMeshDS(); + if ( subDS->NbNodes() == 0 || !n2eMap.count( subDS->GetNodes()->next() )) + continue; + SMDS_NodeIteratorPtr nIt = subDS->GetNodes(); + while ( nIt->more() ) + { + _LayerEdge* edge = n2eMap[ nIt->next() ]; + lEdges.push_back( edge ); + prepareEdgeToShrink( *edge, F, helper, smDS ); + } + } + } + + // Perform shrinking + + TopLoc_Location loc; + Handle(Geom_Surface) surface = BRep_Tool::Surface(F,loc); + bool shrinked = true; + while ( shrinked ) + { + shrinked = false; + for ( unsigned i = 0; i < lEdges.size(); ++i ) + { + _LayerEdge* edge = lEdges[i]; + if ( !edge->_pos.empty() ) + { + SMDS_MeshNode*& node = const_cast< SMDS_MeshNode*& >(edge->_nodes.back()); + //gp_Pnt p = surface->Value( edge->_pos.back().X(), edge->_pos.back().Y() ); + //p.Transform( loc ); + //node->setXYZ( p.X(), p.Y(), p.Z() ); + SMDS_FacePosition* pos = static_cast( node->GetPosition().get() ); + pos->SetUParameter( edge->_pos.back().X() ); + pos->SetVParameter( edge->_pos.back().Y() ); + edge->_pos.pop_back(); + shrinked = true; + } + } + if ( !shrinked ) + break; + + // smoothging + int nbNoImpSteps = 0, badNb = 1, step=0; + bool moved = true; + while ( nbNoImpSteps <= 5 && moved && badNb > 0) + { + dumpFunction(SMESH_Comment("shrinkFace")<first<<"_step"<<++step); // debug + + int oldBadNb = badNb; + badNb = 0; + moved = false; + for ( unsigned i = 0; i < nodesToSmooth.size(); ++i ) + moved = nodesToSmooth[i].Smooth( badNb,surface,loc,helper,refSign ) || moved; + if ( badNb < oldBadNb ) + nbNoImpSteps = 0; + else + nbNoImpSteps++; + + dumpFunctionEnd(); + } + if ( badNb > 0 ) + return error(SMESH_Comment("Can't shrink 2D mesh on face ") << f2sd->first, 0 ); + } + } + + return true; +} + +//================================================================================ +/*! + * \brief Compute positions (UV) to set to a node on edge moved during shrinking + */ +//================================================================================ + +bool _ViscousBuilder::prepareEdgeToShrink( _LayerEdge& edge, + const TopoDS_Face& F, + SMESH_MesherHelper& helper, + const SMESHDS_SubMesh* faceSubMesh) +{ + // Compute UV to follow during shrinking + + const SMDS_MeshNode* srcNode = edge._nodes[0]; + const SMDS_MeshNode* tgtNode = edge._nodes.back(); + + gp_XY srcUV = helper.GetNodeUV( F, srcNode ); + gp_XY tgtUV = helper.GetNodeUV( F, tgtNode ); + gp_Vec2d uvDir( srcUV, tgtUV ); + double uvLen = uvDir.Magnitude(); + uvDir /= uvLen; + + const double minStepSize = uvLen / 20; + double stepSize = uvLen; + SMDS_ElemIteratorPtr fIt = srcNode->GetInverseElementIterator(SMDSAbs_Face); + while ( fIt->more() ) + { + const SMDS_MeshElement* f = fIt->next(); + const int nbNodes = f->NbCornerNodes(); + for ( int i = 0; i < nbNodes; ++i ) + { + const SMDS_MeshNode* n = f->GetNode(i); + if ( n->GetPosition()->GetTypeOfPosition() != SMDS_TOP_FACE ) + continue; + gp_XY uv = helper.GetNodeUV( F, n ); + gp_Vec2d uvDirN( srcUV, uv ); + double proj = uvDirN * uvDir; + if ( proj < stepSize && proj > minStepSize ) + stepSize = proj; + } + } + stepSize *= 0.8; + + const int nbSteps = uvLen / stepSize; + gp_XYZ srcUV0( srcUV.X(), srcUV.Y(), 0 ); + gp_XYZ tgtUV0( tgtUV.X(), tgtUV.Y(), 0 ); + edge._pos.resize( nbSteps ); + edge._pos[0] = tgtUV0; + for ( int i = 1; i < nbSteps-1; ++i ) + { + double r = i / nbSteps; + edge._pos[i] = (1-r) * tgtUV0 + r * srcUV0; + } + + // Replace srcNode by tgtNode in shrinked faces + + const SMDS_MeshNode* nodes[20]; + fIt = srcNode->GetInverseElementIterator(SMDSAbs_Face); + + while ( fIt->more() ) + { + const SMDS_MeshElement* f = fIt->next(); + if ( !faceSubMesh->Contains( f )) + continue; + SMDS_ElemIteratorPtr nIt = f->nodesIterator(); + for ( int iN = 0; iN < f->NbNodes(); ++iN ) + { + const SMDS_MeshNode* n = static_cast( nIt->next() ); + nodes[iN] = ( n == srcNode ? tgtNode : n ); + } + helper.GetMeshDS()->ChangeElementNodes( f, nodes, f->NbNodes() ); + } + + return true; +} + +//================================================================================ +/*! + * \brief Perform laplacian smooth + * \retval bool - true if the node has been moved + */ +//================================================================================ + +bool _SmoothNode::Smooth(int& badNb, + Handle(Geom_Surface)& surface, + TopLoc_Location& loc, + SMESH_MesherHelper& helper, + const double refSign) +{ + const TopoDS_Face& face = TopoDS::Face( helper.GetSubShape() ); + + // compute new UV for the node + gp_XY newPos (0,0); + for ( unsigned i = 0; i < _simplices.size(); ++i ) + newPos += helper.GetNodeUV( face, _simplices[i]._nPrev ); + newPos /= _simplices.size(); + + // count quality metrics (orientation) of triangles around the node + int nbOkBefore = 0; + gp_XY tgtUV = helper.GetNodeUV( face, _node ); + for ( unsigned i = 0; i < _simplices.size(); ++i ) + nbOkBefore += _simplices[i].IsForward( tgtUV, face, helper, refSign ); + + int nbOkAfter = 0; + for ( unsigned i = 0; i < _simplices.size(); ++i ) + nbOkAfter += _simplices[i].IsForward( newPos, face, helper, refSign ); + + if ( nbOkAfter < nbOkBefore ) + return false; + + gp_Pnt p = surface->Value( newPos.X(), newPos.Y() ); + p.Transform( loc ); + const_cast< SMDS_MeshNode* >( _node )->setXYZ( p.X(), p.Y(), p.Z() ); + + dumpMove( _node ); + + badNb += _simplices.size() - nbOkAfter; + return ( (tgtUV-newPos).SquareModulus() > 1e-10 ); +} + +//================================================================================ +/*! + * \brief Delete _SolidData + */ +//================================================================================ + +_SolidData::~_SolidData() +{ + for ( unsigned i = 0; i < _edges.size(); ++i ) + delete _edges[i]; + _edges.clear(); +} diff --git a/src/StdMeshers/StdMeshers_ViscousLayers.hxx b/src/StdMeshers/StdMeshers_ViscousLayers.hxx new file mode 100644 index 000000000..ebfa2563f --- /dev/null +++ b/src/StdMeshers/StdMeshers_ViscousLayers.hxx @@ -0,0 +1,93 @@ +// Copyright (C) 2007-2011 CEA/DEN, EDF R&D, OPEN CASCADE +// +// 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_ViscousLayers.hxx +// Created : Wed Dec 1 15:15:34 2010 +// Author : Edward AGAPOV (eap) + +#ifndef __StdMeshers_ViscousLayers_HXX__ +#define __StdMeshers_ViscousLayers_HXX__ + +#include "SMESH_StdMeshers.hxx" + +#include "SMESH_Hypothesis.hxx" +#include "StdMeshers_ProxyMesh.hxx" + +#include + +/*! + * \brief Hypothesis defining parameters of viscous layers + */ +class STDMESHERS_EXPORT StdMeshers_ViscousLayers : public SMESH_Hypothesis +{ +public: + StdMeshers_ViscousLayers(int hypId, int studyId, SMESH_Gen* gen); + + // Set faces to exclude from treatment + void SetIgnoreFaces(const std::vector& faceIds); + std::vector GetIgnoreFaces() const { return _ignoreFaceIds; } + + // Set total thickness of layers of prisms + void SetTotalThickness(double thickness); + double GetTotalThickness() const { return _thickness; } + + // Set number of layers of prisms + void SetNumberLayers(int nb); + int GetNumberLayers() const { return _nbLayers; } + + // Set factor (>1.0) of growth of layer thickness towards inside of mesh + void SetStretchFactor(double factor); + double GetStretchFactor() const { return _stretchFactor; } + + // Computes temporary 2D mesh to be used by 3D algorithm. + // Return StdMeshers_ProxyMesh for each SOLID in theShape + StdMeshers_ProxyMesh::Ptr Compute(SMESH_Mesh& theMesh, + const TopoDS_Shape& theShape) const; + + virtual std::ostream & SaveTo(std::ostream & save); + virtual std::istream & LoadFrom(std::istream & load); + + /*! + * \brief Initialize my parameter values by the mesh built on the geometry + * \param theMesh - the built mesh + * \param theShape - the geometry of interest + * \retval bool - true if parameter values have been successfully defined + * + * Just return false as this hypothesis does not have parameters values + */ + virtual bool SetParametersByMesh(const SMESH_Mesh* theMesh, const TopoDS_Shape& theShape); + + /*! + * \brief Initialize my parameter values by default parameters. + * \retval bool - true if parameter values have been successfully defined + */ + virtual bool SetParametersByDefaults(const TDefaults& dflts, const SMESH_Mesh* theMesh=0) + { return false; } + + static const char* GetHypType() { return "ViscousLayers"; } + + private: + + std::vector _ignoreFaceIds; + int _nbLayers; + double _thickness; + double _stretchFactor; +}; + +#endif diff --git a/src/StdMeshersGUI/StdMeshersGUI_StdHypothesisCreator.cxx b/src/StdMeshersGUI/StdMeshersGUI_StdHypothesisCreator.cxx index 9595e67a0..1cd4f9f94 100644 --- a/src/StdMeshersGUI/StdMeshersGUI_StdHypothesisCreator.cxx +++ b/src/StdMeshersGUI/StdMeshersGUI_StdHypothesisCreator.cxx @@ -666,6 +666,25 @@ QString StdMeshersGUI_StdHypothesisCreator::storeParams() const QCheckBox* toCopyGroups = widget< QCheckBox >( 2 ); h->SetCopySourceMesh( toCopyMesh->isChecked(), toCopyGroups->isChecked()); } + else if( hypType()=="ViscousLayers" ) + { + StdMeshers::StdMeshers_ViscousLayers_var h = + StdMeshers::StdMeshers_ViscousLayers::_narrow( hypothesis() ); + + h->SetTotalThickness( params[0].myValue.toDouble() ); + /* */ h->SetParameters(aVariablesList.join(":").toLatin1().constData()); + h->SetNumberLayers ( params[1].myValue.toInt() ); + /* */ h->SetParameters(aVariablesList.join(":").toLatin1().constData()); + h->SetStretchFactor ( params[2].myValue.toInt() ); + /* */ h->SetParameters(aVariablesList.join(":").toLatin1().constData()); + + if ( StdMeshersGUI_SubShapeSelectorWdg* idsWg = + widget< StdMeshersGUI_SubShapeSelectorWdg >( 3 )) + { + h->SetIgnoreFaces( idsWg->GetListOfIDs() ); + //h->SetObjectEntry( idsWg->GetMainShapeEntry() ); + } + } else if( hypType()=="QuadrangleParams" ) { StdMeshers::StdMeshers_QuadrangleParams_var h = @@ -1099,6 +1118,45 @@ bool StdMeshersGUI_StdHypothesisCreator::stdParams( ListOfStdParams& p ) const aQCheckBox->setEnabled( toCopyMesh ); customWidgets()->append( aQCheckBox ); } + else if( hypType()=="ViscousLayers" ) + { + StdMeshers::StdMeshers_ViscousLayers_var h = + StdMeshers::StdMeshers_ViscousLayers::_narrow( hyp ); + + item.myName = tr( "SMESH_TOTAL_THICKNESS" ); + if(!initVariableName(aParameters,item,0)) + item.myValue = h->GetTotalThickness(); + p.append( item ); + customWidgets()->append (0); + + item.myName = tr( "SMESH_NUMBER_OF_LAYERS" ); + if(!initVariableName(aParameters,item,1)) + item.myValue = h->GetNumberLayers(); + p.append( item ); + customWidgets()->append (0); + + item.myName = tr( "SMESH_STRETCH_FACTOR" ); + if(!initVariableName(aParameters,item,2)) + item.myValue = h->GetStretchFactor(); + p.append( item ); + customWidgets()->append (0); + + QString aMainEntry = SMESHGUI_GenericHypothesisCreator::getMainShapeEntry(); + if ( !aMainEntry.isEmpty() ) + { + item.myName = tr( "SMESH_FACES_WO_LAYERS" ); + p.append( item ); + + StdMeshersGUI_SubShapeSelectorWdg* idsWg = + new StdMeshersGUI_SubShapeSelectorWdg(0,TopAbs_FACE); + + idsWg->SetGeomShapeEntry( aMainEntry ); + idsWg->SetMainShapeEntry( aMainEntry ); + idsWg->SetListOfIDs( h->GetIgnoreFaces() ); + idsWg->showPreview( true ); + customWidgets()->append ( idsWg ); + } + } else if (hypType() == "QuadrangleParams") { StdMeshers::StdMeshers_QuadrangleParams_var h = @@ -1108,9 +1166,8 @@ bool StdMeshersGUI_StdHypothesisCreator::stdParams( ListOfStdParams& p ) const p.append(item); StdMeshersGUI_SubShapeSelectorWdg* aDirectionWidget = - new StdMeshersGUI_SubShapeSelectorWdg(); + new StdMeshersGUI_SubShapeSelectorWdg(0, TopAbs_VERTEX); aDirectionWidget->SetMaxSize(1); - aDirectionWidget->SetSubShType(TopAbs_VERTEX); QString anEntry = SMESHGUI_GenericHypothesisCreator::getShapeEntry(); QString aMainEntry = SMESHGUI_GenericHypothesisCreator::getMainShapeEntry(); if (anEntry == "") @@ -1118,9 +1175,9 @@ bool StdMeshersGUI_StdHypothesisCreator::stdParams( ListOfStdParams& p ) const aDirectionWidget->SetGeomShapeEntry(anEntry); aDirectionWidget->SetMainShapeEntry(aMainEntry); if (!isCreation()) { - SMESH::long_array_var aVec = new SMESH::long_array; int vertID = h->GetTriaVertex(); if (vertID > 0) { + SMESH::long_array_var aVec = new SMESH::long_array; aVec->length(1); aVec[0] = vertID; aDirectionWidget->SetListOfIDs(aVec); @@ -1148,50 +1205,66 @@ bool StdMeshersGUI_StdHypothesisCreator::stdParams( ListOfStdParams& p ) const //================================================================================ /*! * \brief tune "standard" control - * \param w - control widget - * \param int - parameter index + * \param w - control widget + * \param int - parameter index */ //================================================================================ void StdMeshersGUI_StdHypothesisCreator::attuneStdWidget (QWidget* w, const int) const { SMESHGUI_SpinBox* sb = w->inherits( "SMESHGUI_SpinBox" ) ? ( SMESHGUI_SpinBox* )w : 0; - if( hypType()=="LocalLength" && sb ) + if ( sb ) { - if (sb->objectName() == tr("SMESH_LOCAL_LENGTH_PARAM")) + if( hypType()=="LocalLength" ) + { + if (sb->objectName() == tr("SMESH_LOCAL_LENGTH_PARAM")) + sb->RangeStepAndValidator( VALUE_SMALL, VALUE_MAX, 1.0, "length_precision" ); + else if (sb->objectName() == tr("SMESH_LOCAL_LENGTH_PRECISION")) + sb->RangeStepAndValidator( 0.0, 1.0, 0.05, "len_tol_precision" ); + } + else if( hypType()=="Arithmetic1D" ) + { + sb->RangeStepAndValidator( VALUE_SMALL, VALUE_MAX, 1.0, "parametric_precision" ); + } + else if( hypType()=="MaxLength" ) + { sb->RangeStepAndValidator( VALUE_SMALL, VALUE_MAX, 1.0, "length_precision" ); - else if (sb->objectName() == tr("SMESH_LOCAL_LENGTH_PRECISION")) - sb->RangeStepAndValidator( 0.0, 1.0, 0.05, "len_tol_precision" ); - } - else if( hypType()=="Arithmetic1D" && sb ) - { - sb->RangeStepAndValidator( VALUE_SMALL, VALUE_MAX, 1.0, "parametric_precision" ); - } - else if( hypType()=="MaxLength" && sb ) - { - sb->RangeStepAndValidator( VALUE_SMALL, VALUE_MAX, 1.0, "length_precision" ); - sb->setEnabled( !widget< QCheckBox >( 1 )->isChecked() ); - } - else if( hypType()=="MaxElementArea" && sb ) - { - sb->RangeStepAndValidator( VALUE_SMALL_2, VALUE_MAX_2, 1.0, "area_precision" ); - } - else if( hypType()=="MaxElementVolume" && sb ) - { - sb->RangeStepAndValidator( VALUE_SMALL_3, VALUE_MAX_3, 1.0, "vol_precision" ); - } - else if( hypType()=="StartEndLength" && sb ) - { - sb->RangeStepAndValidator( VALUE_SMALL, VALUE_MAX, 1.0, "length_precision" ); - } - else if( hypType()=="Deflection1D" && sb ) - { - sb->RangeStepAndValidator( VALUE_SMALL, VALUE_MAX, 1.0, "parametric_precision" ); - } - else if ( sb ) // default validator for possible ancestors - { - sb->RangeStepAndValidator( VALUE_SMALL, VALUE_MAX, 1.0, "length_precision" ); + sb->setEnabled( !widget< QCheckBox >( 1 )->isChecked() ); + } + else if( hypType()=="MaxElementArea" ) + { + sb->RangeStepAndValidator( VALUE_SMALL_2, VALUE_MAX_2, 1.0, "area_precision" ); + } + else if( hypType()=="MaxElementVolume" ) + { + sb->RangeStepAndValidator( VALUE_SMALL_3, VALUE_MAX_3, 1.0, "vol_precision" ); + } + else if( hypType()=="StartEndLength" ) + { + sb->RangeStepAndValidator( VALUE_SMALL, VALUE_MAX, 1.0, "length_precision" ); + } + else if( hypType()=="Deflection1D" ) + { + sb->RangeStepAndValidator( VALUE_SMALL, VALUE_MAX, 1.0, "parametric_precision" ); + } + else if( hypType()=="ViscousLayers" ) + { + if (sb->objectName() == tr("SMESH_STRETCH_FACTOR")) + sb->RangeStepAndValidator( 1.0, VALUE_MAX, 0.1, "parametric_precision" ); + else + sb->RangeStepAndValidator( VALUE_SMALL, VALUE_MAX, 1.0, "length_precision" ); + } + else // default validator for possible ancestors + { + sb->RangeStepAndValidator( VALUE_SMALL, VALUE_MAX, 1.0, "length_precision" ); + } } +// else if ( QtxIntSpinBox* ib = w->inherits( "QtxIntSpinBox" ) ? ( QtxIntSpinBox* )w : 0) +// { +// if( hypType()=="ViscousLayers" ) +// { +// } +// } } //================================================================================ @@ -1266,6 +1339,7 @@ QString StdMeshersGUI_StdHypothesisCreator::hypTypeName( const QString& t ) cons types.insert( "SegmentLengthAroundVertex", "SEGMENT_LENGTH_AROUND_VERTEX" ); types.insert( "MaxLength", "MAX_LENGTH" ); types.insert( "QuadrangleParams", "QUADRANGLE_PARAMS" ); + types.insert( "ViscousLayers", "VISCOUS_LAYERS" ); } QString res; diff --git a/src/StdMeshersGUI/StdMeshers_images.ts b/src/StdMeshersGUI/StdMeshers_images.ts index 87444b56a..172b74854 100644 --- a/src/StdMeshersGUI/StdMeshers_images.ts +++ b/src/StdMeshersGUI/StdMeshers_images.ts @@ -57,6 +57,10 @@ ICON_DLG_MAX_LENGTH mesh_hypo_length.png + + ICON_DLG_VISCOUS_LAYERS + mesh_hypo_viscous_layers.png + ICON_DLG_MAX_ELEMENT_AREA mesh_hypo_area.png diff --git a/src/StdMeshersGUI/StdMeshers_msg_en.ts b/src/StdMeshersGUI/StdMeshers_msg_en.ts index 75888dfa3..2235e628e 100644 --- a/src/StdMeshersGUI/StdMeshers_msg_en.ts +++ b/src/StdMeshersGUI/StdMeshers_msg_en.ts @@ -139,6 +139,10 @@ SMESH_MAX_LENGTH_HYPOTHESIS Max Length + + SMESH_VISCOUS_LAYERS_HYPOTHESIS + Viscous Layers + SMESH_USE_PREESTIMATED_LENGTH Use preestimated length @@ -147,6 +151,10 @@ SMESH_MAX_LENGTH_TITLE Hypothesis Construction + + SMESH_VISCOUS_LAYERS_TITLE + Hypothesis Construction + SMESH_MAX_ELEMENT_AREA_HYPOTHESIS Max. Element Area @@ -191,6 +199,18 @@ SMESH_NO_CONV No conversion + + SMESH_TOTAL_THICKNESS + Total thickness + + + SMESH_STRETCH_FACTOR + Stretch factor + + + SMESH_FACES_WO_LAYERS + Faces without layers + SMESH_NUMBER_OF_LAYERS Number of Layers diff --git a/src/StdMeshers_I/Makefile.am b/src/StdMeshers_I/Makefile.am index 17d7c9f6f..a44406b6b 100644 --- a/src/StdMeshers_I/Makefile.am +++ b/src/StdMeshers_I/Makefile.am @@ -67,7 +67,8 @@ salomeinclude_HEADERS = \ StdMeshers_ImportSource1D_i.hxx \ StdMeshers_ImportSource2D_i.hxx \ StdMeshers_Import_1D_i.hxx \ - StdMeshers_Import_1D2D_i.hxx + StdMeshers_Import_1D2D_i.hxx \ + StdMeshers_ViscousLayers_i.hxx # Libraries targets lib_LTLIBRARIES = libStdMeshersEngine.la @@ -113,7 +114,8 @@ dist_libStdMeshersEngine_la_SOURCES = \ StdMeshers_ImportSource1D_i.cxx \ StdMeshers_ImportSource2D_i.cxx \ StdMeshers_Import_1D_i.cxx \ - StdMeshers_Import_1D2D_i.cxx + StdMeshers_Import_1D2D_i.cxx \ + StdMeshers_ViscousLayers_i.cxx # additionnal information to compil and link file libStdMeshersEngine_la_CPPFLAGS = \ diff --git a/src/StdMeshers_I/StdMeshers_ViscousLayers_i.cxx b/src/StdMeshers_I/StdMeshers_ViscousLayers_i.cxx new file mode 100644 index 000000000..b461843e8 --- /dev/null +++ b/src/StdMeshers_I/StdMeshers_ViscousLayers_i.cxx @@ -0,0 +1,215 @@ +// Copyright (C) 2007-2010 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 +// + +// SMESH SMESH_I : idl implementation based on 'SMESH' unit's calsses +// File : StdMeshers_ViscousLayers_i.cxx +// Module : SMESH +// +#include "StdMeshers_ViscousLayers_i.hxx" + +#include "SMESH_Gen.hxx" +#include "SMESH_Gen_i.hxx" +#include "SMESH_PythonDump.hxx" +//#include "StdMeshers_ObjRefUlils.hxx" + +#include "Utils_CorbaException.hxx" +#include "utilities.h" + +#include + +#include CORBA_SERVER_HEADER(SMESH_Group) + +using namespace std; + +//============================================================================= +/*! + * StdMeshers_ViscousLayers_i::StdMeshers_ViscousLayers_i + * + * Constructor + */ +//============================================================================= + +StdMeshers_ViscousLayers_i::StdMeshers_ViscousLayers_i( PortableServer::POA_ptr thePOA, + int theStudyId, + ::SMESH_Gen* theGenImpl ) + : SALOME::GenericObj_i( thePOA ), + SMESH_Hypothesis_i( thePOA ) +{ + MESSAGE( "StdMeshers_ViscousLayers_i::StdMeshers_ViscousLayers_i" ); + myBaseImpl = new ::StdMeshers_ViscousLayers( theGenImpl->GetANewId(), + theStudyId, + theGenImpl ); +} + +//============================================================================= +/*! + * StdMeshers_ViscousLayers_i::~StdMeshers_ViscousLayers_i + * + * Destructor + */ +//============================================================================= + +StdMeshers_ViscousLayers_i::~StdMeshers_ViscousLayers_i() +{ + MESSAGE( "StdMeshers_ViscousLayers_i::~StdMeshers_ViscousLayers_i" ); +} + +//================================================================================ +/*! + * \brief + */ +//================================================================================ + +void StdMeshers_ViscousLayers_i::SetIgnoreFaces(const ::SMESH::long_array& faceIDs) +throw ( SALOME::SALOME_Exception ) +{ + vector ids( faceIDs.length() ); + for ( unsigned i = 0; i < ids.size(); ++i ) + if (( ids[i] = faceIDs[i] ) < 1 ) + THROW_SALOME_CORBA_EXCEPTION( "Invalid face id", SALOME::BAD_PARAM ); + GetImpl()->SetIgnoreFaces( ids ); + SMESH::TPythonDump() << _this() << ".SetIgnoreFaces( " << faceIDs << " )"; +} + +//================================================================================ +/*! + * \brief + */ +//================================================================================ + +SMESH::long_array* StdMeshers_ViscousLayers_i::GetIgnoreFaces() +{ + vector idsVec = GetImpl()->GetIgnoreFaces(); + SMESH::long_array_var ids = new SMESH::long_array; + ids->length( idsVec.size() ); + for ( unsigned i = 0; i < idsVec.size(); ++i ) + ids[i] = idsVec[i]; + return ids._retn(); +} + +//================================================================================ +/*! + * \brief + */ +//================================================================================ + +void StdMeshers_ViscousLayers_i::SetTotalThickness(::CORBA::Double thickness) +throw ( SALOME::SALOME_Exception ) +{ + if ( thickness < 1e-100 ) + THROW_SALOME_CORBA_EXCEPTION( "Invalid thickness", SALOME::BAD_PARAM ); + GetImpl()->SetTotalThickness(thickness); + SMESH::TPythonDump() << _this() << ".SetTotalThickness( " << thickness << " )"; +} + +//================================================================================ +/*! + * \brief + */ +//================================================================================ + +::CORBA::Double StdMeshers_ViscousLayers_i::GetTotalThickness() +{ + return GetImpl()->GetTotalThickness(); +} + +//================================================================================ +/*! + * \brief + * \param nb - + */ +//================================================================================ + +void StdMeshers_ViscousLayers_i::SetNumberLayers(::CORBA::Short nb) +throw ( SALOME::SALOME_Exception ) +{ + if ( nb < 1 ) + THROW_SALOME_CORBA_EXCEPTION( "Invalid number of layers", SALOME::BAD_PARAM ); + GetImpl()->SetNumberLayers( nb ); + SMESH::TPythonDump() << _this() << ".SetNumberLayers( " << nb << " )"; +} + +//================================================================================ +/*! + * \brief + */ +//================================================================================ + +::CORBA::Short StdMeshers_ViscousLayers_i::GetNumberLayers() +{ + return CORBA::Short( GetImpl()->GetNumberLayers() ); +} + +//================================================================================ +/*! + * \brief + * \param factor - + */ +//================================================================================ + +void StdMeshers_ViscousLayers_i::SetStretchFactor(::CORBA::Double factor) +throw ( SALOME::SALOME_Exception ) +{ + if ( factor < 1 ) + THROW_SALOME_CORBA_EXCEPTION( "Invalid stretch factor, it must be >= 1.0", SALOME::BAD_PARAM ); + GetImpl()->SetStretchFactor(factor); + SMESH::TPythonDump() << _this() << ".SetStretchFactor( " << factor << " )"; +} + +//================================================================================ +/*! + * \brief + * + */ +//================================================================================ + +::CORBA::Double StdMeshers_ViscousLayers_i::GetStretchFactor() +{ + return GetImpl()->GetStretchFactor(); +} + +//============================================================================= +/*! + * Get implementation + */ +//============================================================================= + +::StdMeshers_ViscousLayers* StdMeshers_ViscousLayers_i::GetImpl() +{ + MESSAGE( "StdMeshers_ViscousLayers_i::GetImpl" ); + return ( ::StdMeshers_ViscousLayers* )myBaseImpl; +} + +//================================================================================ +/*! + * \brief Verify whether hypothesis supports given entity type + * \param type - dimension (see SMESH::Dimension enumeration) + * \retval CORBA::Boolean - TRUE if dimension is supported, FALSE otherwise + * + * Verify whether hypothesis supports given entity type (see SMESH::Dimension enumeration) + */ +//================================================================================ +CORBA::Boolean StdMeshers_ViscousLayers_i::IsDimSupported( SMESH::Dimension type ) +{ + return type == SMESH::DIM_3D; +} + diff --git a/src/StdMeshers_I/StdMeshers_ViscousLayers_i.hxx b/src/StdMeshers_I/StdMeshers_ViscousLayers_i.hxx new file mode 100644 index 000000000..29699eb8b --- /dev/null +++ b/src/StdMeshers_I/StdMeshers_ViscousLayers_i.hxx @@ -0,0 +1,81 @@ +// Copyright (C) 2007-2010 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 +// + +// SMESH SMESH_I : idl implementation based on 'SMESH' unit's calsses +// File : StdMeshers_ViscousLayers_i.hxx +// Module : SMESH +// +#ifndef _SMESH_ViscousLayers_I_HXX_ +#define _SMESH_ViscousLayers_I_HXX_ + +#include "SMESH_StdMeshers_I.hxx" + +#include +#include CORBA_SERVER_HEADER(SMESH_BasicHypothesis) + +#include "SMESH_Hypothesis_i.hxx" +#include "StdMeshers_ViscousLayers.hxx" + +class SMESH_Gen; + +class STDMESHERS_I_EXPORT StdMeshers_ViscousLayers_i: + public virtual POA_StdMeshers::StdMeshers_ViscousLayers, + public virtual SMESH_Hypothesis_i +{ + public: + // Constructor + StdMeshers_ViscousLayers_i( PortableServer::POA_ptr thePOA, + int theStudyId, + ::SMESH_Gen* theGenImpl ); + // Destructor + virtual ~StdMeshers_ViscousLayers_i(); + + void SetIgnoreFaces(const ::SMESH::long_array& faceIDs) throw ( SALOME::SALOME_Exception ); + SMESH::long_array* GetIgnoreFaces(); + + void SetTotalThickness(::CORBA::Double thickness) throw ( SALOME::SALOME_Exception ); + ::CORBA::Double GetTotalThickness(); + + void SetNumberLayers(::CORBA::Short nb) throw ( SALOME::SALOME_Exception ); + ::CORBA::Short GetNumberLayers(); + + void SetStretchFactor(::CORBA::Double factor) throw ( SALOME::SALOME_Exception ); + ::CORBA::Double GetStretchFactor(); + + // Get implementation + ::StdMeshers_ViscousLayers* GetImpl(); + + // Verify whether hypothesis supports given entity type + CORBA::Boolean IsDimSupported( SMESH::Dimension type ); + + // Redefined Persistence +// virtual char* SaveTo(); +// virtual void LoadFrom( const char* theStream ); +// virtual void UpdateAsMeshesRestored(); + + private: + //SMESH::string_array_var _groupEntries; + //std::vector< std::string > _groupIDs; +}; + +#endif + diff --git a/src/StdMeshers_I/StdMeshers_i.cxx b/src/StdMeshers_I/StdMeshers_i.cxx index a8f6a9824..3145a081d 100644 --- a/src/StdMeshers_I/StdMeshers_i.cxx +++ b/src/StdMeshers_I/StdMeshers_i.cxx @@ -71,6 +71,7 @@ #include "StdMeshers_RadialQuadrangle_1D2D_i.hxx" #include "StdMeshers_Import_1D_i.hxx" #include "StdMeshers_Import_1D2D_i.hxx" +#include "StdMeshers_ViscousLayers_i.hxx" template class StdHypothesisCreator_i:public HypothesisCreator_i @@ -149,6 +150,8 @@ STDMESHERS_I_EXPORT aCreator = new StdHypothesisCreator_i; else if (strcmp(aHypName, "ImportSource2D") == 0) aCreator = new StdHypothesisCreator_i; + else if (strcmp(aHypName, "ViscousLayers") == 0) + aCreator = new StdHypothesisCreator_i; // Algorithms else if (strcmp(aHypName, "Regular_1D") == 0)