X-Git-Url: http://git.salome-platform.org/gitweb/?p=modules%2Fsmesh.git;a=blobdiff_plain;f=src%2FSMESHUtils%2FSMESH_MeshAlgos.cxx;h=a2c9c10368fe357f5ee0c6011b6ac255774f8ff5;hp=957828474e306b0d3bb07286179f454aaf297c1c;hb=98ec6be586ce93a33c242c6ce1f90b609ce31493;hpb=32db05b07f6505e78211bc3cfb5921a6a5885242 diff --git a/src/SMESHUtils/SMESH_MeshAlgos.cxx b/src/SMESHUtils/SMESH_MeshAlgos.cxx index 957828474..a2c9c1036 100644 --- a/src/SMESHUtils/SMESH_MeshAlgos.cxx +++ b/src/SMESHUtils/SMESH_MeshAlgos.cxx @@ -1,4 +1,4 @@ -// Copyright (C) 2007-2014 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2019 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 @@ -23,11 +23,12 @@ // Created : Tue Apr 30 18:00:36 2013 // Author : Edward AGAPOV (eap) -// This file holds some low level algorithms extracted from SMESH_MeshEditor +// Initially this file held some low level algorithms extracted from SMESH_MeshEditor // to make them accessible from Controls package #include "SMESH_MeshAlgos.hxx" +#include "ObjectPool.hxx" #include "SMDS_FaceOfNodes.hxx" #include "SMDS_LinearEdge.hxx" #include "SMDS_Mesh.hxx" @@ -35,6 +36,8 @@ #include "SMDS_VolumeTool.hxx" #include "SMESH_OctreeNode.hxx" +#include + #include #include #include @@ -42,11 +45,12 @@ #include #include #include +#include #include #include -using namespace std; +#include //======================================================================= /*! @@ -60,16 +64,25 @@ struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher /*! * \brief Constructor */ - SMESH_NodeSearcherImpl( const SMDS_Mesh* theMesh ) + SMESH_NodeSearcherImpl( const SMDS_Mesh* theMesh = 0, + SMDS_ElemIteratorPtr theElemIt = SMDS_ElemIteratorPtr() ) { myMesh = ( SMDS_Mesh* ) theMesh; TIDSortedNodeSet nodes; if ( theMesh ) { - SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator(/*idInceasingOrder=*/true); + SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator(); while ( nIt->more() ) nodes.insert( nodes.end(), nIt->next() ); } + else if ( theElemIt ) + { + while ( theElemIt->more() ) + { + const SMDS_MeshElement* e = theElemIt->next(); + nodes.insert( e->begin_nodes(), e->end_nodes() ); + } + } myOctreeNode = new SMESH_OctreeNode(nodes) ; // get max size of a leaf box @@ -99,21 +112,22 @@ struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher */ const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt ) { - map dist2Nodes; + std::map dist2Nodes; myOctreeNode->NodesAround( thePnt.Coord(), dist2Nodes, myHalfLeafSize ); if ( !dist2Nodes.empty() ) return dist2Nodes.begin()->second; - list nodes; + + std::vector nodes; //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize ); double minSqDist = DBL_MAX; if ( nodes.empty() ) // get all nodes of OctreeNode's closest to thePnt { // sort leafs by their distance from thePnt - typedef map< double, SMESH_OctreeNode* > TDistTreeMap; + typedef std::multimap< double, SMESH_OctreeNode* > TDistTreeMap; TDistTreeMap treeMap; - list< SMESH_OctreeNode* > treeList; - list< SMESH_OctreeNode* >::iterator trIt; + std::list< SMESH_OctreeNode* > treeList; + std::list< SMESH_OctreeNode* >::iterator trIt; treeList.push_back( myOctreeNode ); gp_XYZ pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() ); @@ -132,9 +146,7 @@ struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher { const Bnd_B3d& box = *tree->getBox(); double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() )); - pair it_in = treeMap.insert( make_pair( sqDist, tree )); - if ( !it_in.second ) // not unique distance to box center - treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree )); + treeMap.insert( std::make_pair( sqDist, tree )); } } // find distance after which there is no sense to check tree's @@ -151,23 +163,35 @@ struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher if ( sqDist_tree->first > sqLimit ) break; SMESH_OctreeNode* tree = sqDist_tree->second; - tree->NodesAround( tree->GetNodeIterator()->next(), &nodes ); + tree->AllNodesAround( tree->GetNodeIterator()->next(), &nodes ); } } // find closest among nodes minSqDist = DBL_MAX; const SMDS_MeshNode* closestNode = 0; - list::iterator nIt = nodes.begin(); - for ( ; nIt != nodes.end(); ++nIt ) { - double sqDist = thePnt.SquareDistance( SMESH_TNodeXYZ( *nIt ) ); + for ( size_t i = 0; i < nodes.size(); ++i ) + { + double sqDist = thePnt.SquareDistance( SMESH_NodeXYZ( nodes[ i ])); if ( minSqDist > sqDist ) { - closestNode = *nIt; + closestNode = nodes[ i ]; minSqDist = sqDist; } } return closestNode; } + //--------------------------------------------------------------------- + /*! + * \brief Finds nodes located within a tolerance near a point + */ + int FindNearPoint(const gp_Pnt& point, + const double tolerance, + std::vector< const SMDS_MeshNode* >& foundNodes) + { + myOctreeNode->NodesAround( point.Coord(), foundNodes, tolerance ); + return foundNodes.size(); + } + //--------------------------------------------------------------------- /*! * \brief Destructor @@ -203,19 +227,21 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint() { public: + typedef boost::container::flat_set< const SMDS_MeshElement*, TIDCompare > TElemSeq; + ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt = SMDS_ElemIteratorPtr(), double tolerance = NodeRadius ); - void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems ); - void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems); - void getElementsInSphere ( const gp_XYZ& center, - const double radius, TIDSortedElemSet& foundElems); - size_t getSize() { return std::max( _size, _elements.size() ); } - virtual ~ElementBndBoxTree(); + void getElementsNearPoint( const gp_Pnt& point, TElemSeq& foundElems ); + void getElementsNearLine ( const gp_Ax1& line, TElemSeq& foundElems ); + void getElementsInBox ( const Bnd_B3d& box, TElemSeq& foundElems ); + void getElementsInSphere ( const gp_XYZ& center, const double radius, TElemSeq& foundElems ); + ElementBndBoxTree* getLeafAtPoint( const gp_XYZ& point ); + int getNbElements(); protected: - ElementBndBoxTree():_size(0) {} + ElementBndBoxTree() {} SMESH_Octree* newChild() const { return new ElementBndBoxTree; } void buildChildrenData(); Bnd_B3d* buildRootBox(); @@ -224,11 +250,23 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint() struct ElementBox : public Bnd_B3d { const SMDS_MeshElement* _element; - int _refCount; // an ElementBox can be included in several tree branches - ElementBox(const SMDS_MeshElement* elem, double tolerance); + void init(const SMDS_MeshElement* elem, double tolerance); }; - vector< ElementBox* > _elements; - size_t _size; + std::vector< ElementBox* > _elements; + + typedef ObjectPool< ElementBox > TElementBoxPool; + + //!< allocator of ElementBox's and SMESH_TreeLimit + struct LimitAndPool : public SMESH_TreeLimit + { + TElementBoxPool _elBoPool; + LimitAndPool():SMESH_TreeLimit( MaxLevel, /*minSize=*/0. ) {} + }; + LimitAndPool* getLimitAndPool() const + { + SMESH_TreeLimit* limitAndPool = const_cast< SMESH_TreeLimit* >( myLimit ); + return static_cast< LimitAndPool* >( limitAndPool ); + } }; //================================================================================ @@ -237,32 +275,32 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint() */ //================================================================================ - ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt, double tolerance) - :SMESH_Octree( new SMESH_TreeLimit( MaxLevel, /*minSize=*/0. )) + ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, + SMDSAbs_ElementType elemType, + SMDS_ElemIteratorPtr theElemIt, + double tolerance) + :SMESH_Octree( new LimitAndPool() ) { int nbElems = mesh.GetMeshInfo().NbElements( elemType ); _elements.reserve( nbElems ); + TElementBoxPool& elBoPool = getLimitAndPool()->_elBoPool; + +#ifdef _DEBUG_ + if ( theElemIt && !theElemIt->more() ) + std::cout << "WARNING: ElementBndBoxTree constructed on empty iterator!" << std::endl; +#endif + SMDS_ElemIteratorPtr elemIt = theElemIt ? theElemIt : mesh.elementsIterator( elemType ); while ( elemIt->more() ) - _elements.push_back( new ElementBox( elemIt->next(),tolerance )); - + { + ElementBox* eb = elBoPool.getNew(); + eb->init( elemIt->next(), tolerance ); + _elements.push_back( eb ); + } compute(); } - //================================================================================ - /*! - * \brief Destructor - */ - //================================================================================ - - ElementBndBoxTree::~ElementBndBoxTree() - { - for ( int i = 0; i < _elements.size(); ++i ) - if ( --_elements[i]->_refCount <= 0 ) - delete _elements[i]; - } - //================================================================================ /*! * \brief Return the maximal box @@ -272,7 +310,7 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint() Bnd_B3d* ElementBndBoxTree::buildRootBox() { Bnd_B3d* box = new Bnd_B3d; - for ( int i = 0; i < _elements.size(); ++i ) + for ( size_t i = 0; i < _elements.size(); ++i ) box->Add( *_elements[i] ); return box; } @@ -285,28 +323,24 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint() void ElementBndBoxTree::buildChildrenData() { - for ( int i = 0; i < _elements.size(); ++i ) + for ( size_t i = 0; i < _elements.size(); ++i ) { for (int j = 0; j < 8; j++) { if ( !_elements[i]->IsOut( *myChildren[j]->getBox() )) - { - _elements[i]->_refCount++; ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]); - } } - _elements[i]->_refCount--; } - _size = _elements.size(); + //_size = _elements.size(); SMESHUtils::FreeVector( _elements ); // = _elements.clear() + free memory for (int j = 0; j < 8; j++) { ElementBndBoxTree* child = static_cast( myChildren[j]); - if ( child->_elements.size() <= MaxNbElemsInLeaf ) + if ((int) child->_elements.size() <= MaxNbElemsInLeaf ) child->myIsLeaf = true; - if ( child->_elements.capacity() - child->_elements.size() > 1000 ) + if ( child->isLeaf() && child->_elements.capacity() > child->_elements.size() ) SMESHUtils::CompactVector( child->_elements ); } } @@ -317,15 +351,14 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint() */ //================================================================================ - void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt& point, - TIDSortedElemSet& foundElems) + void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt& point, TElemSeq& foundElems) { if ( getBox()->IsOut( point.XYZ() )) return; if ( isLeaf() ) { - for ( int i = 0; i < _elements.size(); ++i ) + for ( size_t i = 0; i < _elements.size(); ++i ) if ( !_elements[i]->IsOut( point.XYZ() )) foundElems.insert( _elements[i]->_element ); } @@ -342,16 +375,15 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint() */ //================================================================================ - void ElementBndBoxTree::getElementsNearLine( const gp_Ax1& line, - TIDSortedElemSet& foundElems) + void ElementBndBoxTree::getElementsNearLine( const gp_Ax1& line, TElemSeq& foundElems ) { if ( getBox()->IsOut( line )) return; if ( isLeaf() ) { - for ( int i = 0; i < _elements.size(); ++i ) - if ( !_elements[i]->IsOut( line )) + for ( size_t i = 0; i < _elements.size(); ++i ) + if ( !_elements[i]->IsOut( line ) ) foundElems.insert( _elements[i]->_element ); } else @@ -367,16 +399,16 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint() */ //================================================================================ - void ElementBndBoxTree::getElementsInSphere ( const gp_XYZ& center, - const double radius, - TIDSortedElemSet& foundElems) + void ElementBndBoxTree::getElementsInSphere ( const gp_XYZ& center, + const double radius, + TElemSeq& foundElems) { if ( getBox()->IsOut( center, radius )) return; if ( isLeaf() ) { - for ( int i = 0; i < _elements.size(); ++i ) + for ( size_t i = 0; i < _elements.size(); ++i ) if ( !_elements[i]->IsOut( center, radius )) foundElems.insert( _elements[i]->_element ); } @@ -387,19 +419,87 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint() } } + //================================================================================ + /*! + * \brief Return elements from leaves intersecting the box + */ + //================================================================================ + + void ElementBndBoxTree::getElementsInBox( const Bnd_B3d& box, TElemSeq& foundElems ) + { + if ( getBox()->IsOut( box )) + return; + + if ( isLeaf() ) + { + for ( size_t i = 0; i < _elements.size(); ++i ) + if ( !_elements[i]->IsOut( box )) + foundElems.insert( _elements[i]->_element ); + } + else + { + for (int i = 0; i < 8; i++) + ((ElementBndBoxTree*) myChildren[i])->getElementsInBox( box, foundElems ); + } + } + + //================================================================================ + /*! + * \brief Return a leaf including a point + */ + //================================================================================ + + ElementBndBoxTree* ElementBndBoxTree::getLeafAtPoint( const gp_XYZ& point ) + { + if ( getBox()->IsOut( point )) + return 0; + + if ( isLeaf() ) + { + return this; + } + else + { + for (int i = 0; i < 8; i++) + if ( ElementBndBoxTree* l = ((ElementBndBoxTree*) myChildren[i])->getLeafAtPoint( point )) + return l; + } + return 0; + } + + //================================================================================ + /*! + * \brief Return number of elements + */ + //================================================================================ + + int ElementBndBoxTree::getNbElements() + { + int nb = 0; + if ( isLeaf() ) + { + nb = _elements.size(); + } + else + { + for (int i = 0; i < 8; i++) + nb += ((ElementBndBoxTree*) myChildren[i])->getNbElements(); + } + return nb; + } + //================================================================================ /*! * \brief Construct the element box */ //================================================================================ - ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem, double tolerance) + void ElementBndBoxTree::ElementBox::init(const SMDS_MeshElement* elem, double tolerance) { _element = elem; - _refCount = 1; SMDS_ElemIteratorPtr nIt = elem->nodesIterator(); while ( nIt->more() ) - Add( SMESH_TNodeXYZ( nIt->next() )); + Add( SMESH_NodeXYZ( nIt->next() )); Enlarge( tolerance ); } @@ -418,32 +518,56 @@ SMESH_ElementSearcher::~SMESH_ElementSearcher() struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher { - SMDS_Mesh* _mesh; - SMDS_ElemIteratorPtr _meshPartIt; - ElementBndBoxTree* _ebbTree; - SMESH_NodeSearcherImpl* _nodeSearcher; - SMDSAbs_ElementType _elementType; - double _tolerance; - bool _outerFacesFound; - set _outerFaces; // empty means "no internal faces at all" - - SMESH_ElementSearcherImpl( SMDS_Mesh& mesh, SMDS_ElemIteratorPtr elemIt=SMDS_ElemIteratorPtr()) - : _mesh(&mesh),_meshPartIt(elemIt),_ebbTree(0),_nodeSearcher(0),_tolerance(-1),_outerFacesFound(false) {} + SMDS_Mesh* _mesh; + SMDS_ElemIteratorPtr _meshPartIt; + ElementBndBoxTree* _ebbTree [SMDSAbs_NbElementTypes]; + int _ebbTreeHeight[SMDSAbs_NbElementTypes]; + SMESH_NodeSearcherImpl* _nodeSearcher; + SMDSAbs_ElementType _elementType; + double _tolerance; + bool _outerFacesFound; + std::set _outerFaces; // empty means "no internal faces at all" + + SMESH_ElementSearcherImpl( SMDS_Mesh& mesh, + double tol=-1, + SMDS_ElemIteratorPtr elemIt=SMDS_ElemIteratorPtr()) + : _mesh(&mesh),_meshPartIt(elemIt),_nodeSearcher(0),_tolerance(tol),_outerFacesFound(false) + { + for ( int i = 0; i < SMDSAbs_NbElementTypes; ++i ) + { + _ebbTree[i] = NULL; + _ebbTreeHeight[i] = -1; + } + _elementType = SMDSAbs_All; + } virtual ~SMESH_ElementSearcherImpl() { - if ( _ebbTree ) delete _ebbTree; _ebbTree = 0; + for ( int i = 0; i < SMDSAbs_NbElementTypes; ++i ) + { + delete _ebbTree[i]; _ebbTree[i] = NULL; + } if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0; } - virtual int FindElementsByPoint(const gp_Pnt& point, - SMDSAbs_ElementType type, - vector< const SMDS_MeshElement* >& foundElements); + virtual int FindElementsByPoint(const gp_Pnt& point, + SMDSAbs_ElementType type, + std::vector< const SMDS_MeshElement* >& foundElements); virtual TopAbs_State GetPointState(const gp_Pnt& point); virtual const SMDS_MeshElement* FindClosestTo( const gp_Pnt& point, SMDSAbs_ElementType type ); - void GetElementsNearLine( const gp_Ax1& line, - SMDSAbs_ElementType type, - vector< const SMDS_MeshElement* >& foundElems); + virtual void GetElementsNearLine( const gp_Ax1& line, + SMDSAbs_ElementType type, + std::vector< const SMDS_MeshElement* >& foundElems); + virtual void GetElementsInSphere( const gp_XYZ& center, + const double radius, + SMDSAbs_ElementType type, + std::vector< const SMDS_MeshElement* >& foundElems); + virtual void GetElementsInBox( const Bnd_B3d& box, + SMDSAbs_ElementType type, + std::vector< const SMDS_MeshElement* >& foundElems); + virtual gp_XYZ Project(const gp_Pnt& point, + SMDSAbs_ElementType type, + const SMDS_MeshElement** closestElem); double getTolerance(); bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face, const double tolerance, double & param); @@ -452,6 +576,13 @@ struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher { return _outerFaces.empty() || _outerFaces.count(face); } + int getTreeHeight() + { + if ( _ebbTreeHeight[ _elementType ] < 0 ) + _ebbTreeHeight[ _elementType ] = _ebbTree[ _elementType ]->getHeight(); + return _ebbTreeHeight[ _elementType ]; + } + struct TInters //!< data of intersection of the line and the mesh face (used in GetPointState()) { const SMDS_MeshElement* _face; @@ -493,9 +624,9 @@ double SMESH_ElementSearcherImpl::getTolerance() double boxSize = _nodeSearcher->getTree()->maxSize(); _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/; } - else if ( _ebbTree && meshInfo.NbElements() > 0 ) + else if ( _ebbTree[_elementType] && meshInfo.NbElements() > 0 ) { - double boxSize = _ebbTree->maxSize(); + double boxSize = _ebbTree[_elementType]->maxSize(); _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/; } if ( _tolerance == 0 ) @@ -516,16 +647,15 @@ double SMESH_ElementSearcherImpl::getTolerance() } else { - SMDS_ElemIteratorPtr elemIt = - _mesh->elementsIterator( SMDSAbs_ElementType( complexType )); + SMDS_ElemIteratorPtr elemIt = _mesh->elementsIterator( SMDSAbs_ElementType( complexType )); const SMDS_MeshElement* elem = elemIt->next(); - SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator(); + SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator(); SMESH_TNodeXYZ n1( nodeIt->next() ); elemSize = 0; while ( nodeIt->more() ) { double dist = n1.Distance( static_cast( nodeIt->next() )); - elemSize = max( dist, elemSize ); + elemSize = std::max( dist, elemSize ); } } _tolerance = 1e-4 * elemSize; @@ -556,10 +686,10 @@ bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin& lin { GC_MakeSegment edge( SMESH_TNodeXYZ( face->GetNode( i )), SMESH_TNodeXYZ( face->GetNode( (i+1)%nbNodes) )); - anExtCC.Init( lineCurve, edge); + anExtCC.Init( lineCurve, edge.Value() ); if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol) { - Quantity_Parameter pl, pe; + Standard_Real pl, pe; anExtCC.LowerDistanceParameters( pl, pe ); param += pl; if ( ++nbInts == 2 ) @@ -583,10 +713,10 @@ void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerF // and BTW find out if there are internal faces at all. // checked links and links where outer boundary meets internal one - set< SMESH_TLink > visitedLinks, seamLinks; + std::set< SMESH_TLink > visitedLinks, seamLinks; // links to treat with already visited faces sharing them - list < TFaceLink > startLinks; + std::list < TFaceLink > startLinks; // load startLinks with the first outerFace startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace)); @@ -628,26 +758,27 @@ void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerF // direction from the link inside outerFace gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2; // sort all other faces by angle with the dirInOF - map< double, const SMDS_MeshElement* > angle2Face; - set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin(); + std::map< double, const SMDS_MeshElement* > angle2Face; + std::set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin(); for ( ; face != faces.end(); ++face ) { + if ( *face == outerFace ) continue; if ( !SMESH_MeshAlgos::FaceNormal( *face, fNorm, /*normalized=*/false )) continue; gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2; double angle = dirInOF.AngleWithRef( dirInF, n1n2 ); if ( angle < 0 ) angle += 2. * M_PI; - angle2Face.insert( make_pair( angle, *face )); + angle2Face.insert( std::make_pair( angle, *face )); } if ( !angle2Face.empty() ) outerFace2 = angle2Face.begin()->second; } } - // store the found outer face and add its links to continue seaching from + // store the found outer face and add its links to continue searching from if ( outerFace2 ) { - _outerFaces.insert( outerFace ); - int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 ); + _outerFaces.insert( outerFace2 ); + int nbNodes = outerFace2->NbCornerNodes(); for ( int i = 0; i < nbNodes; ++i ) { SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes)); @@ -682,11 +813,12 @@ void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerF //======================================================================= int SMESH_ElementSearcherImpl:: -FindElementsByPoint(const gp_Pnt& point, - SMDSAbs_ElementType type, - vector< const SMDS_MeshElement* >& foundElements) +FindElementsByPoint(const gp_Pnt& point, + SMDSAbs_ElementType type, + std::vector< const SMDS_MeshElement* >& foundElements) { foundElements.clear(); + _elementType = type; double tolerance = getTolerance(); @@ -694,36 +826,39 @@ FindElementsByPoint(const gp_Pnt& point, if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement || type == SMDSAbs_Ball) { if ( !_nodeSearcher ) - _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh ); - - const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point ); - if ( !closeNode ) return foundElements.size(); - - if ( point.Distance( SMESH_TNodeXYZ( closeNode )) > tolerance ) - return foundElements.size(); // to far from any node + { + if ( _meshPartIt ) + _nodeSearcher = new SMESH_NodeSearcherImpl( 0, _meshPartIt ); + else + _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh ); + } + std::vector< const SMDS_MeshNode* > foundNodes; + _nodeSearcher->FindNearPoint( point, tolerance, foundNodes ); if ( type == SMDSAbs_Node ) { - foundElements.push_back( closeNode ); + foundElements.assign( foundNodes.begin(), foundNodes.end() ); } else { - SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( type ); - while ( elemIt->more() ) - foundElements.push_back( elemIt->next() ); + for ( size_t i = 0; i < foundNodes.size(); ++i ) + { + SMDS_ElemIteratorPtr elemIt = foundNodes[i]->GetInverseElementIterator( type ); + while ( elemIt->more() ) + foundElements.push_back( elemIt->next() ); + } } } // ================================================================================= else // elements more complex than 0D { - if ( !_ebbTree || _elementType != type ) + if ( !_ebbTree[type] ) { - if ( _ebbTree ) delete _ebbTree; - _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt, tolerance ); + _ebbTree[_elementType] = new ElementBndBoxTree( *_mesh, type, _meshPartIt, tolerance ); } - TIDSortedElemSet suspectElems; - _ebbTree->getElementsNearPoint( point, suspectElems ); - TIDSortedElemSet::iterator elem = suspectElems.begin(); + ElementBndBoxTree::TElemSeq suspectElems; + _ebbTree[ type ]->getElementsNearPoint( point, suspectElems ); + ElementBndBoxTree::TElemSeq::iterator elem = suspectElems.begin(); for ( ; elem != suspectElems.end(); ++elem ) if ( !SMESH_MeshAlgos::IsOut( *elem, point, tolerance )) foundElements.push_back( *elem ); @@ -744,47 +879,49 @@ SMESH_ElementSearcherImpl::FindClosestTo( const gp_Pnt& point, SMDSAbs_ElementType type ) { const SMDS_MeshElement* closestElem = 0; + _elementType = type; - if ( type == SMDSAbs_Face || type == SMDSAbs_Volume ) + if ( type == SMDSAbs_Face || + type == SMDSAbs_Volume || + type == SMDSAbs_Edge ) { - if ( !_ebbTree || _elementType != type ) - { - if ( _ebbTree ) delete _ebbTree; - _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt ); - } - TIDSortedElemSet suspectElems; - _ebbTree->getElementsNearPoint( point, suspectElems ); + ElementBndBoxTree*& ebbTree = _ebbTree[ type ]; + if ( !ebbTree ) + ebbTree = new ElementBndBoxTree( *_mesh, type, _meshPartIt ); + + ElementBndBoxTree::TElemSeq suspectElems; + ebbTree->getElementsNearPoint( point, suspectElems ); - if ( suspectElems.empty() && _ebbTree->maxSize() > 0 ) + if ( suspectElems.empty() && ebbTree->maxSize() > 0 ) { - gp_Pnt boxCenter = 0.5 * ( _ebbTree->getBox()->CornerMin() + - _ebbTree->getBox()->CornerMax() ); + gp_Pnt boxCenter = 0.5 * ( ebbTree->getBox()->CornerMin() + + ebbTree->getBox()->CornerMax() ); double radius = -1; - if ( _ebbTree->getBox()->IsOut( point.XYZ() )) - radius = point.Distance( boxCenter ) - 0.5 * _ebbTree->maxSize(); + if ( ebbTree->getBox()->IsOut( point.XYZ() )) + radius = point.Distance( boxCenter ) - 0.5 * ebbTree->maxSize(); if ( radius < 0 ) - radius = _ebbTree->maxSize() / pow( 2., _ebbTree->getHeight()) / 2; - while ( suspectElems.empty() ) + radius = ebbTree->maxSize() / pow( 2., getTreeHeight()) / 2; + while ( suspectElems.empty() && radius < 1e100 ) { - _ebbTree->getElementsInSphere( point.XYZ(), radius, suspectElems ); + ebbTree->getElementsInSphere( point.XYZ(), radius, suspectElems ); radius *= 1.1; } } double minDist = std::numeric_limits::max(); - multimap< double, const SMDS_MeshElement* > dist2face; - TIDSortedElemSet::iterator elem = suspectElems.begin(); + std::multimap< double, const SMDS_MeshElement* > dist2face; + ElementBndBoxTree::TElemSeq::iterator elem = suspectElems.begin(); for ( ; elem != suspectElems.end(); ++elem ) { double dist = SMESH_MeshAlgos::GetDistance( *elem, point ); if ( dist < minDist + 1e-10) { minDist = dist; - dist2face.insert( dist2face.begin(), make_pair( dist, *elem )); + dist2face.insert( dist2face.begin(), std::make_pair( dist, *elem )); } } if ( !dist2face.empty() ) { - multimap< double, const SMDS_MeshElement* >::iterator d2f = dist2face.begin(); + std::multimap< double, const SMDS_MeshElement* >::iterator d2f = dist2face.begin(); closestElem = d2f->second; // if there are several elements at the same distance, select one // with GC closest to the point @@ -829,33 +966,35 @@ SMESH_ElementSearcherImpl::FindClosestTo( const gp_Pnt& point, TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point) { + _elementType = SMDSAbs_Face; + double tolerance = getTolerance(); - if ( !_ebbTree || _elementType != SMDSAbs_Face ) - { - if ( _ebbTree ) delete _ebbTree; - _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face, _meshPartIt ); - } + + ElementBndBoxTree*& ebbTree = _ebbTree[ SMDSAbs_Face ]; + if ( !ebbTree ) + ebbTree = new ElementBndBoxTree( *_mesh, _elementType, _meshPartIt ); + // Algo: analyse transition of a line starting at the point through mesh boundary; // try three lines parallel to axis of the coordinate system and perform rough // analysis. If solution is not clear perform thorough analysis. const int nbAxes = 3; gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() }; - map< double, TInters > paramOnLine2TInters[ nbAxes ]; - list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line - multimap< int, int > nbInt2Axis; // to find the simplest case + std::map< double, TInters > paramOnLine2TInters[ nbAxes ]; + std::list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line + std::multimap< int, int > nbInt2Axis; // to find the simplest case for ( int axis = 0; axis < nbAxes; ++axis ) { gp_Ax1 lineAxis( point, axisDir[axis]); gp_Lin line ( lineAxis ); - TIDSortedElemSet suspectFaces; // faces possibly intersecting the line - _ebbTree->getElementsNearLine( lineAxis, suspectFaces ); + ElementBndBoxTree::TElemSeq suspectFaces; // faces possibly intersecting the line + ebbTree->getElementsNearLine( lineAxis, suspectFaces ); // Intersect faces with the line - map< double, TInters > & u2inters = paramOnLine2TInters[ axis ]; - TIDSortedElemSet::iterator face = suspectFaces.begin(); + std::map< double, TInters > & u2inters = paramOnLine2TInters[ axis ]; + ElementBndBoxTree::TElemSeq::iterator face = suspectFaces.begin(); for ( ; face != suspectFaces.end(); ++face ) { // get face plane @@ -873,9 +1012,10 @@ TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point) } else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 ) { + double tol = 1e-4 * Sqrt( fNorm.Modulus() ); gp_Pnt intersectionPoint = intersection.Point(1); - if ( !SMESH_MeshAlgos::IsOut( *face, intersectionPoint, tolerance )) - u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm ))); + if ( !SMESH_MeshAlgos::IsOut( *face, intersectionPoint, tol )) + u2inters.insert( std::make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm ))); } } // Analyse intersections roughly @@ -899,7 +1039,7 @@ TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point) if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 ) return TopAbs_IN; - nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis )); + nbInt2Axis.insert( std::make_pair( std::min( nbIntBeforePoint, nbIntAfterPoint ), axis )); if ( _outerFacesFound ) break; // pass to thorough analysis @@ -913,29 +1053,29 @@ TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point) for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo ) { - multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin(); + std::multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin(); for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis ) { int axis = nb_axis->second; - map< double, TInters > & u2inters = paramOnLine2TInters[ axis ]; + std::map< double, TInters > & u2inters = paramOnLine2TInters[ axis ]; gp_Ax1 lineAxis( point, axisDir[axis]); gp_Lin line ( lineAxis ); // add tangent intersections to u2inters double param; - list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin(); + std::list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin(); for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt ) if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param )) - u2inters.insert(make_pair( param, *tgtInt )); + u2inters.insert( std::make_pair( param, *tgtInt )); tangentInters[ axis ].clear(); // Count intersections before and after the point excluding touching ones. // If hasPositionInfo we count intersections of outer boundary only int nbIntBeforePoint = 0, nbIntAfterPoint = 0; - double f = numeric_limits::max(), l = -numeric_limits::max(); - map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1; + double f = std::numeric_limits::max(), l = -std::numeric_limits::max(); + std::map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1; bool ok = ! u_int1->second._coincides; while ( ok && u_int1 != u2inters.end() ) { @@ -953,16 +1093,19 @@ TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point) // skip tangent intersections int nbTgt = 0; - const SMDS_MeshElement* prevFace = u_int1->second._face; - while ( ok && u_int2->second._coincides ) + if ( u_int2 != u2inters.end() ) { - if ( SMESH_MeshAlgos::GetCommonNodes(prevFace , u_int2->second._face).empty() ) - ok = false; - else + const SMDS_MeshElement* prevFace = u_int1->second._face; + while ( ok && u_int2->second._coincides ) { - nbTgt++; - u_int2++; - ok = ( u_int2 != u2inters.end() ); + if ( SMESH_MeshAlgos::GetCommonNodes(prevFace , u_int2->second._face).empty() ) + ok = false; + else + { + nbTgt++; + u_int2++; + ok = ( u_int2 != u2inters.end() ); + } } } if ( !ok ) break; @@ -981,8 +1124,8 @@ TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point) // decide if we skipped a touching intersection if ( nbSamePnt + nbTgt > 0 ) { - double minDot = numeric_limits::max(), maxDot = -numeric_limits::max(); - map< double, TInters >::iterator u_int = u_int1; + double minDot = std::numeric_limits::max(), maxDot = -minDot; + std::map< double, TInters >::iterator u_int = u_int1; for ( ; u_int != u_int2; ++u_int ) { if ( u_int->second._coincides ) continue; @@ -1035,7 +1178,7 @@ TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point) if ( !hasPositionInfo ) { // gather info on faces position - is face in the outer boundary or not - map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ]; + std::map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ]; findOuterBoundary( u2inters.begin()->second._face ); } @@ -1050,18 +1193,157 @@ TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point) */ //======================================================================= -void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1& line, - SMDSAbs_ElementType type, - vector< const SMDS_MeshElement* >& foundElems) +void SMESH_ElementSearcherImpl:: +GetElementsNearLine( const gp_Ax1& line, + SMDSAbs_ElementType type, + std::vector< const SMDS_MeshElement* >& foundElems) +{ + _elementType = type; + ElementBndBoxTree*& ebbTree = _ebbTree[ type ]; + if ( !ebbTree ) + ebbTree = new ElementBndBoxTree( *_mesh, _elementType, _meshPartIt ); + + ElementBndBoxTree::TElemSeq elems; + ebbTree->getElementsNearLine( line, elems ); + + foundElems.insert( foundElems.end(), elems.begin(), elems.end() ); +} + +//======================================================================= +/* + * Return elements whose bounding box intersects a sphere + */ +//======================================================================= + +void SMESH_ElementSearcherImpl:: +GetElementsInSphere( const gp_XYZ& center, + const double radius, + SMDSAbs_ElementType type, + std::vector< const SMDS_MeshElement* >& foundElems) +{ + _elementType = type; + ElementBndBoxTree*& ebbTree = _ebbTree[ type ]; + if ( !ebbTree ) + ebbTree = new ElementBndBoxTree( *_mesh, _elementType, _meshPartIt ); + + ElementBndBoxTree::TElemSeq elems; + ebbTree->getElementsInSphere( center, radius, elems ); + + foundElems.insert( foundElems.end(), elems.begin(), elems.end() ); +} + +//======================================================================= +/* + * Return elements whose bounding box intersects a given bounding box + */ +//======================================================================= + +void SMESH_ElementSearcherImpl:: +GetElementsInBox( const Bnd_B3d& box, + SMDSAbs_ElementType type, + std::vector< const SMDS_MeshElement* >& foundElems) +{ + _elementType = type; + ElementBndBoxTree*& ebbTree = _ebbTree[ type ]; + if ( !ebbTree ) + ebbTree = new ElementBndBoxTree( *_mesh, _elementType, _meshPartIt, getTolerance() ); + + ElementBndBoxTree::TElemSeq elems; + ebbTree->getElementsInBox( box, elems ); + + foundElems.insert( foundElems.end(), elems.begin(), elems.end() ); +} + +//======================================================================= +/* + * \brief Return a projection of a given point to a mesh. + * Optionally return the closest element + */ +//======================================================================= + +gp_XYZ SMESH_ElementSearcherImpl::Project(const gp_Pnt& point, + SMDSAbs_ElementType type, + const SMDS_MeshElement** closestElem) { - if ( !_ebbTree || _elementType != type ) + _elementType = type; + if ( _mesh->GetMeshInfo().NbElements( _elementType ) == 0 ) + throw SALOME_Exception( LOCALIZED( "No elements of given type in the mesh" )); + + ElementBndBoxTree*& ebbTree = _ebbTree[ _elementType ]; + if ( !ebbTree ) + ebbTree = new ElementBndBoxTree( *_mesh, _elementType, _meshPartIt ); + + gp_XYZ p = point.XYZ(); + ElementBndBoxTree* ebbLeaf = ebbTree->getLeafAtPoint( p ); + const Bnd_B3d* box = ebbLeaf ? ebbLeaf->getBox() : ebbTree->getBox(); + gp_XYZ pMin = box->CornerMin(), pMax = box->CornerMax(); + double radius = Precision::Infinite(); + if ( ebbLeaf || !box->IsOut( p )) + { + for ( int i = 1; i <= 3; ++i ) + { + double d = 0.5 * ( pMax.Coord(i) - pMin.Coord(i) ); + if ( d > Precision::Confusion() ) + radius = Min( d, radius ); + } + if ( !ebbLeaf ) + radius /= ebbTree->getHeight( /*full=*/true ); + } + else // p outside of box + { + for ( int i = 1; i <= 3; ++i ) + { + double d = 0; + if ( point.Coord(i) < pMin.Coord(i) ) + d = pMin.Coord(i) - point.Coord(i); + else if ( point.Coord(i) > pMax.Coord(i) ) + d = point.Coord(i) - pMax.Coord(i); + if ( d > Precision::Confusion() ) + radius = Min( d, radius ); + } + } + + ElementBndBoxTree::TElemSeq elems; + ebbTree->getElementsInSphere( p, radius, elems ); + while ( elems.empty() && radius < 1e100 ) { - if ( _ebbTree ) delete _ebbTree; - _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt ); + radius *= 1.1; + ebbTree->getElementsInSphere( p, radius, elems ); + } + gp_XYZ proj, bestProj; + const SMDS_MeshElement* elem = 0; + double minDist = Precision::Infinite(); + ElementBndBoxTree::TElemSeq::iterator e = elems.begin(); + for ( ; e != elems.end(); ++e ) + { + double d = SMESH_MeshAlgos::GetDistance( *e, point, &proj ); + if ( d < minDist ) + { + bestProj = proj; + elem = *e; + minDist = d; + } } - TIDSortedElemSet suspectFaces; // elements possibly intersecting the line - _ebbTree->getElementsNearLine( line, suspectFaces ); - foundElems.assign( suspectFaces.begin(), suspectFaces.end()); + if ( minDist > radius ) + { + ElementBndBoxTree::TElemSeq elems2; + ebbTree->getElementsInSphere( p, minDist, elems2 ); + for ( e = elems2.begin(); e != elems2.end(); ++e ) + { + if ( elems.count( *e )) + continue; + double d = SMESH_MeshAlgos::GetDistance( *e, point, &proj ); + if ( d < minDist ) + { + bestProj = proj; + elem = *e; + minDist = d; + } + } + } + if ( closestElem ) *closestElem = elem; + + return bestProj; } //======================================================================= @@ -1079,56 +1361,58 @@ bool SMESH_MeshAlgos::IsOut( const SMDS_MeshElement* element, const gp_Pnt& poin // get ordered nodes - vector< gp_XYZ > xyz; - vector nodeList; + std::vector< SMESH_TNodeXYZ > xyz; xyz.reserve( element->NbNodes()+1 ); - SMDS_ElemIteratorPtr nodeIt = element->nodesIterator(); - if ( element->IsQuadratic() ) { - nodeIt = element->interlacedNodesElemIterator(); - // if (const SMDS_VtkFace* f=dynamic_cast(element)) - // nodeIt = f->interlacedNodesElemIterator(); - // else if (const SMDS_VtkEdge* e =dynamic_cast(element)) - // nodeIt = e->interlacedNodesElemIterator(); - } - while ( nodeIt->more() ) - { - SMESH_TNodeXYZ node = nodeIt->next(); - xyz.push_back( node ); - nodeList.push_back(node._node); - } + SMDS_NodeIteratorPtr nodeIt = element->interlacedNodesIterator(); + for ( int i = 0; nodeIt->more(); ++i ) + xyz.push_back( SMESH_TNodeXYZ( nodeIt->next() )); - int i, nbNodes = (int) nodeList.size(); // central node of biquadratic is missing + int i, nbNodes = (int) xyz.size(); // central node of biquadratic is missing if ( element->GetType() == SMDSAbs_Face ) // -------------------------------------------------- { // compute face normal gp_Vec faceNorm(0,0,0); xyz.push_back( xyz.front() ); - nodeList.push_back( nodeList.front() ); for ( i = 0; i < nbNodes; ++i ) { gp_Vec edge1( xyz[i+1], xyz[i]); gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] ); faceNorm += edge1 ^ edge2; } - double normSize = faceNorm.Magnitude(); - if ( normSize <= tol ) + double fNormSize = faceNorm.Magnitude(); + if ( fNormSize <= tol ) { // degenerated face: point is out if it is out of all face edges for ( i = 0; i < nbNodes; ++i ) { - SMDS_LinearEdge edge( nodeList[i], nodeList[i+1] ); + SMDS_LinearEdge edge( xyz[i]._node, xyz[i+1]._node ); if ( !IsOut( &edge, point, tol )) return false; } return true; } - faceNorm /= normSize; + faceNorm /= fNormSize; // check if the point lays on face plane gp_Vec n2p( xyz[0], point ); - if ( fabs( n2p * faceNorm ) > tol ) - return true; // not on face plane + double dot = n2p * faceNorm; + if ( Abs( dot ) > tol ) // not on face plane + { + bool isOut = true; + if ( nbNodes > 3 ) // maybe the face is not planar + { + double elemThick = 0; + for ( i = 1; i < nbNodes; ++i ) + { + gp_Vec n2n( xyz[0], xyz[i] ); + elemThick = Max( elemThick, Abs( n2n * faceNorm )); + } + isOut = Abs( dot ) > elemThick + tol; + } + if ( isOut ) + return isOut; + } // check if point is out of face boundary: // define it by closest transition of a ray point->infinity through face boundary @@ -1137,11 +1421,12 @@ bool SMESH_MeshAlgos::IsOut( const SMDS_MeshElement* element, const gp_Pnt& poin // to find intersections of the ray with the boundary. gp_Vec ray = n2p; gp_Vec plnNorm = ray ^ faceNorm; - normSize = plnNorm.Magnitude(); - if ( normSize <= tol ) return false; // point coincides with the first node - plnNorm /= normSize; - // for each node of the face, compute its signed distance to the plane - vector dist( nbNodes + 1); + double n2pSize = plnNorm.Magnitude(); + if ( n2pSize <= tol ) return false; // point coincides with the first node + if ( n2pSize * n2pSize > fNormSize * 100 ) return true; // point is very far + plnNorm /= n2pSize; + // for each node of the face, compute its signed distance to the cutting plane + std::vector dist( nbNodes + 1); for ( i = 0; i < nbNodes; ++i ) { gp_Vec n2p( xyz[i], point ); @@ -1150,12 +1435,12 @@ bool SMESH_MeshAlgos::IsOut( const SMDS_MeshElement* element, const gp_Pnt& poin dist.back() = dist.front(); // find the closest intersection int iClosest = -1; - double rClosest, distClosest = 1e100;; + double rClosest = 0, distClosest = 1e100; gp_Pnt pClosest; for ( i = 0; i < nbNodes; ++i ) { double r; - if ( fabs( dist[i]) < tol ) + if ( fabs( dist[i] ) < tol ) r = 0.; else if ( fabs( dist[i+1]) < tol ) r = 1.; @@ -1164,17 +1449,14 @@ bool SMESH_MeshAlgos::IsOut( const SMDS_MeshElement* element, const gp_Pnt& poin else continue; // no intersection gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r; - gp_Vec p2int ( point, pInt); - if ( p2int * ray > -tol ) // right half-space + gp_Vec p2int( point, pInt); + double intDist = p2int.SquareMagnitude(); + if ( intDist < distClosest ) { - double intDist = p2int.SquareMagnitude(); - if ( intDist < distClosest ) - { - iClosest = i; - rClosest = r; - pClosest = pInt; - distClosest = intDist; - } + iClosest = i; + rClosest = r; + pClosest = pInt; + distClosest = intDist; } } if ( iClosest < 0 ) @@ -1188,7 +1470,7 @@ bool SMESH_MeshAlgos::IsOut( const SMDS_MeshElement* element, const gp_Pnt& poin if ( rClosest > 0. && rClosest < 1. ) // not node intersection return out; - // ray pass through a face node; analyze transition through an adjacent edge + // the ray passes through a face node; analyze transition through an adjacent edge gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ]; gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ]; gp_Vec edgeAdjacent( p1, p2 ); @@ -1198,28 +1480,39 @@ bool SMESH_MeshAlgos::IsOut( const SMDS_MeshElement* element, const gp_Pnt& poin bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0; return covexCorner ? (out || out2) : (out && out2); } + if ( element->GetType() == SMDSAbs_Edge ) // -------------------------------------------------- { // point is out of edge if it is NOT ON any straight part of edge // (we consider quadratic edge as being composed of two straight parts) for ( i = 1; i < nbNodes; ++i ) { - gp_Vec edge( xyz[i-1], xyz[i]); - gp_Vec n1p ( xyz[i-1], point); - double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude(); - if ( dist > tol ) + gp_Vec edge( xyz[i-1], xyz[i] ); + gp_Vec n1p ( xyz[i-1], point ); + double u = ( edge * n1p ) / edge.SquareMagnitude(); // param [0,1] on the edge + if ( u <= 0. ) { + if ( n1p.SquareMagnitude() < tol * tol ) + return false; continue; - gp_Vec n2p( xyz[i], point ); - if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol ) + } + if ( u >= 1. ) { + if ( point.SquareDistance( xyz[i] ) < tol * tol ) + return false; + continue; + } + gp_XYZ proj = ( 1. - u ) * xyz[i-1] + u * xyz[i]; // projection of the point on the edge + double dist2 = point.SquareDistance( proj ); + if ( dist2 > tol * tol ) continue; return false; // point is ON this part } return true; } + // Node or 0D element ------------------------------------------------------------------------- { gp_Vec n2p ( xyz[0], point ); - return n2p.Magnitude() <= tol; + return n2p.SquareMagnitude() > tol * tol; } return true; } @@ -1236,7 +1529,8 @@ namespace // . RIGHT . // . . enum PositionName { POS_LEFT = 1, POS_VERTEX = 2, POS_RIGHT = 4, //POS_ON = 8, - POS_ALL = POS_LEFT | POS_RIGHT | POS_VERTEX }; + POS_ALL = POS_LEFT | POS_RIGHT | POS_VERTEX, + POS_MAX = POS_RIGHT }; struct PointPos { PositionName _name; @@ -1253,9 +1547,9 @@ namespace //================================================================================ /*! - * \brief Return of a point relative to a segment + * \brief Return position of a point relative to a segment * \param point2D - the point to analyze position of - * \param xyVec - end points of segments + * \param segEnds - end points of segments * \param index0 - 0-based index of the first point of segment * \param posToFindOut - flags of positions to detect * \retval PointPos - point position @@ -1300,18 +1594,21 @@ namespace //======================================================================= double SMESH_MeshAlgos::GetDistance( const SMDS_MeshElement* elem, - const gp_Pnt& point ) + const gp_Pnt& point, + gp_XYZ* closestPnt ) { switch ( elem->GetType() ) { case SMDSAbs_Volume: - return GetDistance( dynamic_cast( elem ), point); + return GetDistance( static_cast( elem ), point, closestPnt ); case SMDSAbs_Face: - return GetDistance( dynamic_cast( elem ), point); + return GetDistance( static_cast( elem ), point, closestPnt ); case SMDSAbs_Edge: - return GetDistance( dynamic_cast( elem ), point); + return GetDistance( static_cast( elem ), point, closestPnt ); case SMDSAbs_Node: + if ( closestPnt ) *closestPnt = SMESH_TNodeXYZ( elem ); return point.Distance( SMESH_TNodeXYZ( elem )); + default:; } return -1; } @@ -1325,15 +1622,41 @@ double SMESH_MeshAlgos::GetDistance( const SMDS_MeshElement* elem, //======================================================================= double SMESH_MeshAlgos::GetDistance( const SMDS_MeshFace* face, - const gp_Pnt& point ) + const gp_Pnt& point, + gp_XYZ* closestPnt ) { - double badDistance = -1; + const double badDistance = -1; if ( !face ) return badDistance; + int nbCorners = face->NbCornerNodes(); + if ( nbCorners > 3 ) + { + std::vector< const SMDS_MeshNode* > nodes; + int nbTria = SMESH_MeshAlgos::Triangulate().GetTriangles( face, nodes ); + + double minDist = Precision::Infinite(); + gp_XYZ cp; + for ( int i = 0; i < 3 * nbTria; i += 3 ) + { + SMDS_FaceOfNodes triangle( nodes[i], nodes[i+1], nodes[i+2] ); + double dist = GetDistance( &triangle, point, closestPnt ); + if ( dist < minDist ) + { + minDist = dist; + if ( closestPnt ) + cp = *closestPnt; + } + } + + if ( closestPnt ) + *closestPnt = cp; + return minDist; + } + // coordinates of nodes (medium nodes, if any, ignored) typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > TXyzIterator; - vector xyz( TXyzIterator( face->nodesIterator()), TXyzIterator() ); - xyz.resize( face->NbCornerNodes()+1 ); + std::vector xyz( TXyzIterator( face->nodesIterator()), TXyzIterator() ); + xyz.resize( 4 ); // transformation to get xyz[0] lies on the origin, xyz[1] lies on the Z axis, // and xyz[2] lies in the XZ plane. This is to pass to 2D space on XZ plane. @@ -1356,8 +1679,8 @@ double SMESH_MeshAlgos::GetDistance( const SMDS_MeshFace* face, trsf.SetTransformation( tgtCS ); // move all the nodes to 2D - vector xy( xyz.size() ); - for ( size_t i = 0;i < xyz.size()-1; ++i ) + std::vector xy( xyz.size() ); + for ( size_t i = 0; i < 3; ++i ) { gp_XYZ p3d = xyz[i]; trsf.Transforms( p3d ); @@ -1371,45 +1694,64 @@ double SMESH_MeshAlgos::GetDistance( const SMDS_MeshFace* face, trsf.Transforms( tmpPnt ); gp_XY point2D( tmpPnt.X(), tmpPnt.Z() ); - // loop on segments of the face to analyze point position ralative to the face - set< PointPos > pntPosSet; + // loop on edges of the face to analyze point position ralative to the face + std::vector< PointPos > pntPosByType[ POS_MAX + 1 ]; for ( size_t i = 1; i < xy.size(); ++i ) { PointPos pos = getPointPosition( point2D, &xy[0], i-1 ); - pntPosSet.insert( pos ); + pntPosByType[ pos._name ].push_back( pos ); } // compute distance - PointPos pos = *pntPosSet.begin(); - // cout << "Face " << face->GetID() << " DIST: "; - switch ( pos._name ) - { - case POS_LEFT: { - // point is most close to a segment - gp_Vec p0p1( point, xyz[ pos._index ] ); - gp_Vec p1p2( xyz[ pos._index ], xyz[ pos._index+1 ]); // segment vector - p1p2.Normalize(); - double projDist = p0p1 * p1p2; // distance projected to the segment - gp_Vec projVec = p1p2 * projDist; - gp_Vec distVec = p0p1 - projVec; - // cout << distVec.Magnitude() << ", SEG " << face->GetNode(pos._index)->GetID() - // << " - " << face->GetNodeWrap(pos._index+1)->GetID() << endl; - return distVec.Magnitude(); - } - case POS_RIGHT: { - // point is inside the face - double distToFacePlane = tmpPnt.Y(); - // cout << distToFacePlane << ", INSIDE " << endl; - return Abs( distToFacePlane ); + + double dist = badDistance; + + if ( pntPosByType[ POS_LEFT ].size() > 0 ) // point is most close to an edge + { + PointPos& pos = pntPosByType[ POS_LEFT ][0]; + + gp_Vec edge( xyz[ pos._index ], xyz[ pos._index+1 ]); + gp_Vec n1p ( xyz[ pos._index ], point ); + double u = ( edge * n1p ) / edge.SquareMagnitude(); // param [0,1] on the edge + gp_XYZ proj = xyz[ pos._index ] + u * edge.XYZ(); // projection on the edge + dist = point.Distance( proj ); + if ( closestPnt ) *closestPnt = proj; } - case POS_VERTEX: { - // point is most close to a node - gp_Vec distVec( point, xyz[ pos._index ]); - // cout << distVec.Magnitude() << " VERTEX " << face->GetNode(pos._index)->GetID() << endl; - return distVec.Magnitude(); + + else if ( pntPosByType[ POS_RIGHT ].size() >= 2 ) // point is inside the face + { + dist = Abs( tmpPnt.Y() ); + if ( closestPnt ) + { + if ( dist < std::numeric_limits::min() ) { + *closestPnt = point.XYZ(); + } + else { + tmpPnt.SetY( 0 ); + trsf.Inverted().Transforms( tmpPnt ); + *closestPnt = tmpPnt; + } + } } + + else if ( pntPosByType[ POS_VERTEX ].size() > 0 ) // point is most close to a node + { + double minDist2 = Precision::Infinite(); + for ( size_t i = 0; i < pntPosByType[ POS_VERTEX ].size(); ++i ) + { + PointPos& pos = pntPosByType[ POS_VERTEX ][i]; + + double d2 = point.SquareDistance( xyz[ pos._index ]); + if ( minDist2 > d2 ) + { + if ( closestPnt ) *closestPnt = xyz[ pos._index ]; + minDist2 = d2; + } + } + dist = Sqrt( minDist2 ); } - return badDistance; + + return dist; } //======================================================================= @@ -1418,9 +1760,45 @@ double SMESH_MeshAlgos::GetDistance( const SMDS_MeshFace* face, */ //======================================================================= -double SMESH_MeshAlgos::GetDistance( const SMDS_MeshEdge* edge, const gp_Pnt& point ) +double SMESH_MeshAlgos::GetDistance( const SMDS_MeshEdge* seg, + const gp_Pnt& point, + gp_XYZ* closestPnt ) { - throw SALOME_Exception(LOCALIZED("not implemented so far")); + double dist = Precision::Infinite(); + if ( !seg ) return dist; + + int i = 0, nbNodes = seg->NbNodes(); + + std::vector< SMESH_TNodeXYZ > xyz( nbNodes ); + for ( SMDS_NodeIteratorPtr nodeIt = seg->interlacedNodesIterator(); nodeIt->more(); i++ ) + xyz[ i ].Set( nodeIt->next() ); + + for ( i = 1; i < nbNodes; ++i ) + { + gp_Vec edge( xyz[i-1], xyz[i] ); + gp_Vec n1p ( xyz[i-1], point ); + double d, u = ( edge * n1p ) / edge.SquareMagnitude(); // param [0,1] on the edge + if ( u <= 0. ) { + if (( d = n1p.SquareMagnitude() ) < dist ) { + dist = d; + if ( closestPnt ) *closestPnt = xyz[i-1]; + } + } + else if ( u >= 1. ) { + if (( d = point.SquareDistance( xyz[i] )) < dist ) { + dist = d; + if ( closestPnt ) *closestPnt = xyz[i]; + } + } + else { + gp_XYZ proj = xyz[i-1] + u * edge.XYZ(); // projection of the point on the edge + if (( d = point.SquareDistance( proj )) < dist ) { + dist = d; + if ( closestPnt ) *closestPnt = proj; + } + } + } + return Sqrt( dist ); } //======================================================================= @@ -1431,7 +1809,9 @@ double SMESH_MeshAlgos::GetDistance( const SMDS_MeshEdge* edge, const gp_Pnt& po */ //======================================================================= -double SMESH_MeshAlgos::GetDistance( const SMDS_MeshVolume* volume, const gp_Pnt& point ) +double SMESH_MeshAlgos::GetDistance( const SMDS_MeshVolume* volume, + const gp_Pnt& point, + gp_XYZ* closestPnt ) { SMDS_VolumeTool vTool( volume ); vTool.SetExternalNormal(); @@ -1439,6 +1819,8 @@ double SMESH_MeshAlgos::GetDistance( const SMDS_MeshVolume* volume, const gp_Pnt double n[3], bc[3]; double minDist = 1e100, dist; + gp_XYZ closeP = point.XYZ(); + bool isOut = false; for ( int iF = 0; iF < vTool.NbFaces(); ++iF ) { // skip a facet with normal not "looking at" the point @@ -1446,7 +1828,7 @@ double SMESH_MeshAlgos::GetDistance( const SMDS_MeshVolume* volume, const gp_Pnt !vTool.GetFaceBaryCenter( iF, bc[0], bc[1], bc[2] )) continue; gp_XYZ bcp = point.XYZ() - gp_XYZ( bc[0], bc[1], bc[2] ); - if ( gp_XYZ( n[0], n[1], n[2] ) * bcp < 1e-6 ) + if ( gp_XYZ( n[0], n[1], n[2] ) * bcp < -1e-12 ) continue; // find distance to a facet @@ -1455,23 +1837,34 @@ double SMESH_MeshAlgos::GetDistance( const SMDS_MeshVolume* volume, const gp_Pnt case 3: { SMDS_FaceOfNodes tmpFace( nodes[0], nodes[ 1*iQ ], nodes[ 2*iQ ] ); - dist = GetDistance( &tmpFace, point ); + dist = GetDistance( &tmpFace, point, closestPnt ); break; } case 4: { SMDS_FaceOfNodes tmpFace( nodes[0], nodes[ 1*iQ ], nodes[ 2*iQ ], nodes[ 3*iQ ]); - dist = GetDistance( &tmpFace, point ); + dist = GetDistance( &tmpFace, point, closestPnt ); break; } default: - vector nvec( nodes, nodes + vTool.NbFaceNodes( iF )); + std::vector nvec( nodes, nodes + vTool.NbFaceNodes( iF )); SMDS_PolygonalFaceOfNodes tmpFace( nvec ); - dist = GetDistance( &tmpFace, point ); + dist = GetDistance( &tmpFace, point, closestPnt ); + } + if ( dist < minDist ) + { + minDist = dist; + isOut = true; + if ( closestPnt ) closeP = *closestPnt; } - minDist = Min( minDist, dist ); } - return minDist; + if ( isOut ) + { + if ( closestPnt ) *closestPnt = closeP; + return minDist; + } + + return 0; // point is inside the volume } //================================================================================ @@ -1502,7 +1895,7 @@ void SMESH_MeshAlgos::GetBarycentricCoords( const gp_XY& p, const double t11 = T22, t12 = -T12, t21 = -T21, t22 = T11; // vector const double r11 = p.X()-t2.X(), r12 = p.Y()-t2.Y(); - // barycentric coordinates: mutiply matrix by vector + // barycentric coordinates: multiply matrix by vector bc0 = (t11 * r11 + t12 * r12)/Tdet; bc1 = (t21 * r11 + t22 * r12)/Tdet; } @@ -1524,14 +1917,12 @@ SMESH_MeshAlgos::FindFaceInSet(const SMDS_MeshNode* n1, int* n2ind) { - int i1, i2; + int i1 = 0, i2 = 0; const SMDS_MeshElement* face = 0; SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face); - //MESSAGE("n1->GetInverseElementIterator(SMDSAbs_Face) " << invElemIt); while ( invElemIt->more() && !face ) // loop on inverse faces of n1 { - //MESSAGE("in while ( invElemIt->more() && !face )"); const SMDS_MeshElement* elem = invElemIt->next(); if (avoidSet.count( elem )) continue; @@ -1550,10 +1941,7 @@ SMESH_MeshAlgos::FindFaceInSet(const SMDS_MeshNode* n1, if ( !face && elem->IsQuadratic()) { // analysis for quadratic elements using all nodes - // const SMDS_VtkFace* F = dynamic_cast(elem); - // if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace")); - // use special nodes iterator - SMDS_ElemIteratorPtr anIter = elem->interlacedNodesElemIterator(); + SMDS_NodeIteratorPtr anIter = elem->interlacedNodesIterator(); const SMDS_MeshNode* prevN = static_cast( anIter->next() ); for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ ) { @@ -1564,7 +1952,7 @@ SMESH_MeshAlgos::FindFaceInSet(const SMDS_MeshNode* n1, } else if ( n2 == prevN && n1 == n ) { - face = elem; swap( i1, i2 ); + face = elem; std::swap( i1, i2 ); } prevN = n; } @@ -1575,6 +1963,222 @@ SMESH_MeshAlgos::FindFaceInSet(const SMDS_MeshNode* n1, return face; } +//================================================================================ +/*! + * Return sharp edges of faces and non-manifold ones. Optionally adds existing edges. + */ +//================================================================================ + +std::vector< SMESH_MeshAlgos::Edge > +SMESH_MeshAlgos::FindSharpEdges( SMDS_Mesh* theMesh, + double theAngle, + bool theAddExisting ) +{ + std::vector< Edge > resultEdges; + if ( !theMesh ) return resultEdges; + + typedef std::pair< bool, const SMDS_MeshNode* > TIsSharpAndMedium; + typedef NCollection_DataMap< SMESH_TLink, TIsSharpAndMedium, SMESH_TLink > TLinkSharpMap; + + TLinkSharpMap linkIsSharp( theMesh->NbFaces() ); + TIsSharpAndMedium sharpMedium( true, 0 ); + bool & isSharp = sharpMedium.first; + const SMDS_MeshNode* & nMedium = sharpMedium.second; + + if ( theAddExisting ) + { + for ( SMDS_EdgeIteratorPtr edgeIt = theMesh->edgesIterator(); edgeIt->more(); ) + { + const SMDS_MeshElement* edge = edgeIt->next(); + nMedium = ( edge->IsQuadratic() ) ? edge->GetNode(2) : 0; + linkIsSharp.Bind( SMESH_TLink( edge->GetNode(0), edge->GetNode(1)), sharpMedium ); + } + } + + // check angles between face normals + + const double angleCos = Cos( theAngle * M_PI / 180. ), angleCos2 = angleCos * angleCos; + gp_XYZ norm1, norm2; + std::vector< const SMDS_MeshNode* > faceNodes, linkNodes(2); + std::vector linkFaces; + + int nbSharp = linkIsSharp.Extent(); + for ( SMDS_FaceIteratorPtr faceIt = theMesh->facesIterator(); faceIt->more(); ) + { + const SMDS_MeshElement* face = faceIt->next(); + size_t nbCorners = face->NbCornerNodes(); + + faceNodes.assign( face->begin_nodes(), face->end_nodes() ); + if ( faceNodes.size() == nbCorners ) + faceNodes.resize( nbCorners * 2, 0 ); + + const SMDS_MeshNode* nPrev = faceNodes[ nbCorners-1 ]; + for ( size_t i = 0; i < nbCorners; ++i ) + { + SMESH_TLink link( nPrev, faceNodes[i] ); + if ( !linkIsSharp.IsBound( link )) + { + linkNodes[0] = link.node1(); + linkNodes[1] = link.node2(); + linkFaces.clear(); + theMesh->GetElementsByNodes( linkNodes, linkFaces, SMDSAbs_Face ); + + isSharp = false; + if ( linkFaces.size() > 2 ) + { + isSharp = true; + } + else if ( linkFaces.size() == 2 && + FaceNormal( linkFaces[0], norm1, /*normalize=*/false ) && + FaceNormal( linkFaces[1], norm2, /*normalize=*/false )) + { + double dot = norm1 * norm2; // == cos * |norm1| * |norm2| + if (( dot < 0 ) == ( angleCos < 0 )) + { + double cos2 = dot * dot / norm1.SquareModulus() / norm2.SquareModulus(); + isSharp = ( angleCos < 0 ) ? ( cos2 > angleCos2 ) : ( cos2 < angleCos2 ); + } + else + { + isSharp = ( angleCos > 0 ); + } + } + nMedium = faceNodes[( i-1+nbCorners ) % nbCorners + nbCorners ]; + + linkIsSharp.Bind( link, sharpMedium ); + nbSharp += isSharp; + } + + nPrev = faceNodes[i]; + } + } + + resultEdges.resize( nbSharp ); + TLinkSharpMap::Iterator linkIsSharpIter( linkIsSharp ); + for ( int i = 0; linkIsSharpIter.More() && i < nbSharp; linkIsSharpIter.Next() ) + { + const SMESH_TLink& link = linkIsSharpIter.Key(); + const TIsSharpAndMedium& isSharpMedium = linkIsSharpIter.Value(); + if ( isSharpMedium.first ) + { + Edge & edge = resultEdges[ i++ ]; + edge._node1 = link.node1(); + edge._node2 = link.node2(); + edge._medium = isSharpMedium.second; + } + } + + return resultEdges; +} + +//================================================================================ +/*! + * Distribute all faces of the mesh between groups using given edges as group boundaries + */ +//================================================================================ + +std::vector< std::vector< const SMDS_MeshElement* > > +SMESH_MeshAlgos::SeparateFacesByEdges( SMDS_Mesh* theMesh, const std::vector< Edge >& theEdges ) +{ + std::vector< std::vector< const SMDS_MeshElement* > > groups; + if ( !theMesh ) return groups; + + // build map of face edges (SMESH_TLink) and their faces + + typedef std::vector< const SMDS_MeshElement* > TFaceVec; + typedef NCollection_DataMap< SMESH_TLink, TFaceVec, SMESH_TLink > TFacesByLinks; + TFacesByLinks facesByLink( theMesh->NbFaces() ); + + std::vector< const SMDS_MeshNode* > faceNodes; + for ( SMDS_FaceIteratorPtr faceIt = theMesh->facesIterator(); faceIt->more(); ) + { + const SMDS_MeshElement* face = faceIt->next(); + size_t nbCorners = face->NbCornerNodes(); + + faceNodes.assign( face->begin_nodes(), face->end_nodes() ); + faceNodes.resize( nbCorners + 1 ); + faceNodes[ nbCorners ] = faceNodes[0]; + + face->setIsMarked( false ); + + for ( size_t i = 0; i < nbCorners; ++i ) + { + SMESH_TLink link( faceNodes[i], faceNodes[i+1] ); + TFaceVec* linkFaces = facesByLink.ChangeSeek( link ); + if ( !linkFaces ) + { + linkFaces = facesByLink.Bound( link, TFaceVec() ); + linkFaces->reserve(2); + } + linkFaces->push_back( face ); + } + } + + // remove the given edges from facesByLink map + + for ( size_t i = 0; i < theEdges.size(); ++i ) + { + SMESH_TLink link( theEdges[i]._node1, theEdges[i]._node2 ); + facesByLink.UnBind( link ); + } + + // faces connected via links of facesByLink map form a group + + while ( !facesByLink.IsEmpty() ) + { + groups.push_back( TFaceVec() ); + TFaceVec & group = groups.back(); + + group.push_back( TFacesByLinks::Iterator( facesByLink ).Value()[0] ); + group.back()->setIsMarked( true ); + + for ( size_t iF = 0; iF < group.size(); ++iF ) + { + const SMDS_MeshElement* face = group[iF]; + size_t nbCorners = face->NbCornerNodes(); + faceNodes.assign( face->begin_nodes(), face->end_nodes() ); + faceNodes.resize( nbCorners + 1 ); + faceNodes[ nbCorners ] = faceNodes[0]; + + for ( size_t iN = 0; iN < nbCorners; ++iN ) + { + SMESH_TLink link( faceNodes[iN], faceNodes[iN+1] ); + if ( const TFaceVec* faces = facesByLink.Seek( link )) + { + const TFaceVec& faceNeighbors = *faces; + for ( size_t i = 0; i < faceNeighbors.size(); ++i ) + if ( !faceNeighbors[i]->isMarked() ) + { + group.push_back( faceNeighbors[i] ); + faceNeighbors[i]->setIsMarked( true ); + } + facesByLink.UnBind( link ); + } + } + } + } + + // find faces that are alone in its group; they were not in facesByLink + + int nbInGroups = 0; + for ( size_t i = 0; i < groups.size(); ++i ) + nbInGroups += groups[i].size(); + if ( nbInGroups < theMesh->NbFaces() ) + { + for ( SMDS_FaceIteratorPtr faceIt = theMesh->facesIterator(); faceIt->more(); ) + { + const SMDS_MeshElement* face = faceIt->next(); + if ( !face->isMarked() ) + { + groups.push_back( TFaceVec() ); + groups.back().push_back( face ); + } + } + } + + return groups; +} + //================================================================================ /*! * \brief Calculate normal of a mesh face @@ -1587,7 +2191,7 @@ bool SMESH_MeshAlgos::FaceNormal(const SMDS_MeshElement* F, gp_XYZ& normal, bool return false; normal.SetCoord(0,0,0); - int nbNodes = F->IsQuadratic() ? F->NbNodes()/2 : F->NbNodes(); + int nbNodes = F->NbCornerNodes(); for ( int i = 0; i < nbNodes-2; ++i ) { gp_XYZ p[3]; @@ -1599,7 +2203,7 @@ bool SMESH_MeshAlgos::FaceNormal(const SMDS_MeshElement* F, gp_XYZ& normal, bool normal += ( p[2] - p[1] ) ^ ( p[0] - p[1] ); } double size2 = normal.SquareModulus(); - bool ok = ( size2 > numeric_limits::min() * numeric_limits::min()); + bool ok = ( size2 > std::numeric_limits::min() * std::numeric_limits::min()); if ( normalized && ok ) normal /= sqrt( size2 ); @@ -1611,15 +2215,232 @@ bool SMESH_MeshAlgos::FaceNormal(const SMDS_MeshElement* F, gp_XYZ& normal, bool //purpose : Return nodes common to two elements //======================================================================= -vector< const SMDS_MeshNode*> SMESH_MeshAlgos::GetCommonNodes(const SMDS_MeshElement* e1, - const SMDS_MeshElement* e2) +std::vector< const SMDS_MeshNode*> SMESH_MeshAlgos::GetCommonNodes(const SMDS_MeshElement* e1, + const SMDS_MeshElement* e2) { - vector< const SMDS_MeshNode*> common; + std::vector< const SMDS_MeshNode*> common; for ( int i = 0 ; i < e1->NbNodes(); ++i ) if ( e2->GetNodeIndex( e1->GetNode( i )) >= 0 ) common.push_back( e1->GetNode( i )); return common; } +//================================================================================ +/*! + * \brief Return true if node1 encounters first in the face and node2, after + */ +//================================================================================ + +bool SMESH_MeshAlgos::IsRightOrder( const SMDS_MeshElement* face, + const SMDS_MeshNode* node0, + const SMDS_MeshNode* node1 ) +{ + int i0 = face->GetNodeIndex( node0 ); + int i1 = face->GetNodeIndex( node1 ); + if ( face->IsQuadratic() ) + { + if ( face->IsMediumNode( node0 )) + { + i0 -= ( face->NbNodes()/2 - 1 ); + i1 *= 2; + } + else + { + i1 -= ( face->NbNodes()/2 - 1 ); + i0 *= 2; + } + } + int diff = i1 - i0; + return ( diff == 1 ) || ( diff == -face->NbNodes()+1 ); +} + +//======================================================================= +/*! + * \brief Partition given 1D elements into groups of contiguous edges. + * A node where number of meeting edges != 2 is a group end. + * An optional startNode is used to orient groups it belongs to. + * \return a list of edge groups and a list of corresponding node groups. + * If a group is closed, the first and last nodes of the group are same. + */ +//======================================================================= + +void SMESH_MeshAlgos::Get1DBranches( SMDS_ElemIteratorPtr theEdgeIt, + TElemGroupVector& theEdgeGroups, + TNodeGroupVector& theNodeGroups, + const SMDS_MeshNode* theStartNode ) +{ + if ( !theEdgeIt ) + return; + + // build map of nodes and their adjacent edges + + typedef std::vector< const SMDS_MeshNode* > TNodeVec; + typedef std::vector< const SMDS_MeshElement* > TEdgeVec; + typedef NCollection_DataMap< const SMDS_MeshNode*, TEdgeVec, SMESH_Hasher > TEdgesByNodeMap; + TEdgesByNodeMap edgesByNode; + + while ( theEdgeIt->more() ) + { + const SMDS_MeshElement* edge = theEdgeIt->next(); + if ( edge->GetType() != SMDSAbs_Edge ) + continue; + + const SMDS_MeshNode* nodes[2] = { edge->GetNode(0), edge->GetNode(1) }; + for ( int i = 0; i < 2; ++i ) + { + TEdgeVec* nodeEdges = edgesByNode.ChangeSeek( nodes[i] ); + if ( !nodeEdges ) + { + nodeEdges = edgesByNode.Bound( nodes[i], TEdgeVec() ); + nodeEdges->reserve(2); + } + nodeEdges->push_back( edge ); + } + } + + if ( edgesByNode.IsEmpty() ) + return; + + + // build edge branches + + TElemGroupVector branches(2); + TNodeGroupVector nodeBranches(2); + + while ( !edgesByNode.IsEmpty() ) + { + if ( !theStartNode || !edgesByNode.IsBound( theStartNode )) + { + theStartNode = TEdgesByNodeMap::Iterator( edgesByNode ).Key(); + } + + size_t nbBranches = 0; + bool startIsBranchEnd = false; + + while ( edgesByNode.IsBound( theStartNode )) + { + // initialize a new branch + + ++nbBranches; + if ( branches.size() < nbBranches ) + { + branches.push_back ( TEdgeVec() ); + nodeBranches.push_back( TNodeVec() ); + } + TEdgeVec & branch = branches [ nbBranches - 1 ]; + TNodeVec & nodeBranch = nodeBranches[ nbBranches - 1 ]; + branch.clear(); + nodeBranch.clear(); + { + TEdgeVec& edges = edgesByNode( theStartNode ); + startIsBranchEnd = ( edges.size() != 2 ); + + int nbEdges = 0; + const SMDS_MeshElement* startEdge = 0; + for ( size_t i = 0; i < edges.size(); ++i ) + { + if ( !startEdge && edges[i] ) + { + startEdge = edges[i]; + edges[i] = 0; + } + nbEdges += bool( edges[i] ); + } + if ( nbEdges == 0 ) + edgesByNode.UnBind( theStartNode ); + if ( !startEdge ) + continue; + + branch.push_back( startEdge ); + + nodeBranch.push_back( theStartNode ); + nodeBranch.push_back( branch.back()->GetNode(0) ); + if ( nodeBranch.back() == theStartNode ) + nodeBranch.back() = branch.back()->GetNode(1); + } + + // fill the branch + + bool isBranchEnd = false; + TEdgeVec* edgesPtr; + + while (( !isBranchEnd ) && ( edgesPtr = edgesByNode.ChangeSeek( nodeBranch.back() ))) + { + TEdgeVec& edges = *edgesPtr; + + isBranchEnd = ( edges.size() != 2 ); + + const SMDS_MeshNode* lastNode = nodeBranch.back(); + + switch ( edges.size() ) + { + case 1: + edgesByNode.UnBind( lastNode ); + break; + + case 2: + { + if ( const SMDS_MeshElement* nextEdge = edges[ edges[0] == branch.back() ]) + { + branch.push_back( nextEdge ); + + const SMDS_MeshNode* nextNode = nextEdge->GetNode(0); + if ( nodeBranch.back() == nextNode ) + nextNode = nextEdge->GetNode(1); + nodeBranch.push_back( nextNode ); + } + edgesByNode.UnBind( lastNode ); + break; + } + + default: + int nbEdges = 0; + for ( size_t i = 0; i < edges.size(); ++i ) + { + if ( edges[i] == branch.back() ) + edges[i] = 0; + nbEdges += bool( edges[i] ); + } + if ( nbEdges == 0 ) + edgesByNode.UnBind( lastNode ); + } + } + } // while ( edgesByNode.IsBound( theStartNode )) + + + // put the found branches to the result + + if ( nbBranches == 2 && !startIsBranchEnd ) // join two branches starting at the same node + { + std::reverse( nodeBranches[0].begin(), nodeBranches[0].end() ); + nodeBranches[0].pop_back(); + nodeBranches[0].reserve( nodeBranches[0].size() + nodeBranches[1].size() ); + nodeBranches[0].insert( nodeBranches[0].end(), + nodeBranches[1].begin(), nodeBranches[1].end() ); + + std::reverse( branches[0].begin(), branches[0].end() ); + branches[0].reserve( branches[0].size() + branches[1].size() ); + branches[0].insert( branches[0].end(), branches[1].begin(), branches[1].end() ); + + nodeBranches[1].clear(); + branches[1].clear(); + } + + for ( size_t i = 0; i < nbBranches; ++i ) + { + if ( branches[i].empty() ) + continue; + + theEdgeGroups.push_back( TEdgeVec() ); + theEdgeGroups.back().swap( branches[i] ); + + theNodeGroups.push_back( TNodeVec() ); + theNodeGroups.back().swap( nodeBranches[i] ); + } + + } // while ( !edgesByNode.IsEmpty() ) + + return; +} //======================================================================= /*! @@ -1632,15 +2453,27 @@ SMESH_NodeSearcher* SMESH_MeshAlgos::GetNodeSearcher(SMDS_Mesh& mesh) return new SMESH_NodeSearcherImpl( &mesh ); } +//======================================================================= +/*! + * \brief Return SMESH_NodeSearcher + */ +//======================================================================= + +SMESH_NodeSearcher* SMESH_MeshAlgos::GetNodeSearcher(SMDS_ElemIteratorPtr elemIt) +{ + return new SMESH_NodeSearcherImpl( 0, elemIt ); +} + //======================================================================= /*! * \brief Return SMESH_ElementSearcher */ //======================================================================= -SMESH_ElementSearcher* SMESH_MeshAlgos::GetElementSearcher(SMDS_Mesh& mesh) +SMESH_ElementSearcher* SMESH_MeshAlgos::GetElementSearcher(SMDS_Mesh& mesh, + double tolerance) { - return new SMESH_ElementSearcherImpl( mesh ); + return new SMESH_ElementSearcherImpl( mesh, tolerance ); } //======================================================================= @@ -1650,7 +2483,8 @@ SMESH_ElementSearcher* SMESH_MeshAlgos::GetElementSearcher(SMDS_Mesh& mesh) //======================================================================= SMESH_ElementSearcher* SMESH_MeshAlgos::GetElementSearcher(SMDS_Mesh& mesh, - SMDS_ElemIteratorPtr elemIt) + SMDS_ElemIteratorPtr elemIt, + double tolerance) { - return new SMESH_ElementSearcherImpl( mesh, elemIt ); + return new SMESH_ElementSearcherImpl( mesh, tolerance, elemIt ); }