X-Git-Url: http://git.salome-platform.org/gitweb/?p=modules%2Fsmesh.git;a=blobdiff_plain;f=src%2FSMESHUtils%2FSMESH_MeshAlgos.cxx;h=0fc388e75939e987fed1b662f93419fbce4a79fd;hp=8464e245fe197e6765f100a08498d730211522bb;hb=858b4bff6498075831d120d54f3dfe25566336b9;hpb=8a9d91b414c3f26586dea735c22c7700898a0a1e diff --git a/src/SMESHUtils/SMESH_MeshAlgos.cxx b/src/SMESHUtils/SMESH_MeshAlgos.cxx index 8464e245f..0fc388e75 100644 --- a/src/SMESHUtils/SMESH_MeshAlgos.cxx +++ b/src/SMESHUtils/SMESH_MeshAlgos.cxx @@ -28,6 +28,7 @@ #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 @@ -46,7 +49,7 @@ #include #include -using namespace std; +#include //======================================================================= /*! @@ -67,7 +70,7 @@ struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher 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() ); } @@ -108,21 +111,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() ); @@ -141,9 +145,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 @@ -160,17 +162,17 @@ 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; } } @@ -179,7 +181,7 @@ struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher //--------------------------------------------------------------------- /*! - * \brief Finds nodes located within a tolerance near a point + * \brief Finds nodes located within a tolerance near a point */ int FindNearPoint(const gp_Pnt& point, const double tolerance, @@ -224,16 +226,17 @@ 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 prepare(); // !!!call it before calling the following methods!!! - void getElementsNearPoint( const gp_Pnt& point, vector& foundElems ); - void getElementsNearLine ( const gp_Ax1& line, vector& foundElems); - void getElementsInSphere ( const gp_XYZ& center, - const double radius, - vector& foundElems); + 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 ); protected: ElementBndBoxTree() {} @@ -245,18 +248,16 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint() struct ElementBox : public Bnd_B3d { const SMDS_MeshElement* _element; - bool _isMarked; void init(const SMDS_MeshElement* elem, double tolerance); }; - vector< ElementBox* > _elements; + std::vector< ElementBox* > _elements; typedef ObjectPool< ElementBox > TElementBoxPool; //!< allocator of ElementBox's and SMESH_TreeLimit struct LimitAndPool : public SMESH_TreeLimit { - TElementBoxPool _elBoPool; - std::vector< ElementBox* > _markedElems; + TElementBoxPool _elBoPool; LimitAndPool():SMESH_TreeLimit( MaxLevel, /*minSize=*/0. ) {} }; LimitAndPool* getLimitAndPool() const @@ -337,56 +338,27 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint() } } - //================================================================================ - /*! - * \brief Un-mark all elements - */ - //================================================================================ - - void ElementBndBoxTree::prepare() - { - // TElementBoxPool& elBoPool = getElementBoxPool(); - // for ( size_t i = 0; i < elBoPool.nbElements(); ++i ) - // const_cast< ElementBox* >( elBoPool[ i ])->_isMarked = false; - } - //================================================================================ /*! * \brief Return elements which can include the point */ //================================================================================ - void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt& point, - vector& foundElems) + void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt& point, TElemSeq& foundElems) { if ( getBox()->IsOut( point.XYZ() )) return; if ( isLeaf() ) { - LimitAndPool* pool = getLimitAndPool(); - for ( size_t i = 0; i < _elements.size(); ++i ) - if ( !_elements[i]->IsOut( point.XYZ() ) && - !_elements[i]->_isMarked ) - { - foundElems.push_back( _elements[i]->_element ); - _elements[i]->_isMarked = true; - pool->_markedElems.push_back( _elements[i] ); - } + if ( !_elements[i]->IsOut( point.XYZ() )) + foundElems.insert( _elements[i]->_element ); } else { for (int i = 0; i < 8; i++) ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems ); - - if ( level() == 0 ) - { - LimitAndPool* pool = getLimitAndPool(); - for ( size_t i = 0; i < pool->_markedElems.size(); ++i ) - pool->_markedElems[i]->_isMarked = false; - pool->_markedElems.clear(); - } } } @@ -396,37 +368,21 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint() */ //================================================================================ - void ElementBndBoxTree::getElementsNearLine( const gp_Ax1& line, - vector& foundElems) + void ElementBndBoxTree::getElementsNearLine( const gp_Ax1& line, TElemSeq& foundElems ) { if ( getBox()->IsOut( line )) return; if ( isLeaf() ) { - LimitAndPool* pool = getLimitAndPool(); - for ( size_t i = 0; i < _elements.size(); ++i ) - if ( !_elements[i]->IsOut( line ) && - !_elements[i]->_isMarked ) - { - foundElems.push_back( _elements[i]->_element ); - _elements[i]->_isMarked = true; - pool->_markedElems.push_back( _elements[i] ); - } + if ( !_elements[i]->IsOut( line ) ) + foundElems.insert( _elements[i]->_element ); } else { for (int i = 0; i < 8; i++) ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems ); - - if ( level() == 0 ) - { - LimitAndPool* pool = getLimitAndPool(); - for ( size_t i = 0; i < pool->_markedElems.size(); ++i ) - pool->_markedElems[i]->_isMarked = false; - pool->_markedElems.clear(); - } } } @@ -436,39 +392,72 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint() */ //================================================================================ - void ElementBndBoxTree::getElementsInSphere ( const gp_XYZ& center, - const double radius, - vector& foundElems) + void ElementBndBoxTree::getElementsInSphere ( const gp_XYZ& center, + const double radius, + TElemSeq& foundElems) { if ( getBox()->IsOut( center, radius )) return; if ( isLeaf() ) { - LimitAndPool* pool = getLimitAndPool(); - for ( size_t i = 0; i < _elements.size(); ++i ) - if ( !_elements[i]->IsOut( center, radius ) && - !_elements[i]->_isMarked ) - { - foundElems.push_back( _elements[i]->_element ); - _elements[i]->_isMarked = true; - pool->_markedElems.push_back( _elements[i] ); - } + if ( !_elements[i]->IsOut( center, radius )) + foundElems.insert( _elements[i]->_element ); } else { for (int i = 0; i < 8; i++) ((ElementBndBoxTree*) myChildren[i])->getElementsInSphere( center, radius, foundElems ); + } + } - if ( level() == 0 ) - { - LimitAndPool* pool = getLimitAndPool(); - for ( size_t i = 0; i < pool->_markedElems.size(); ++i ) - pool->_markedElems[i]->_isMarked = false; - pool->_markedElems.clear(); - } + //================================================================================ + /*! + * \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; } //================================================================================ @@ -480,7 +469,6 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint() void ElementBndBoxTree::ElementBox::init(const SMDS_MeshElement* elem, double tolerance) { _element = elem; - _isMarked = false; SMDS_ElemIteratorPtr nIt = elem->nodesIterator(); while ( nIt->more() ) Add( SMESH_NodeXYZ( nIt->next() )); @@ -502,15 +490,15 @@ SMESH_ElementSearcher::~SMESH_ElementSearcher() struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher { - SMDS_Mesh* _mesh; - SMDS_ElemIteratorPtr _meshPartIt; - ElementBndBoxTree* _ebbTree [SMDSAbs_NbElementTypes]; - int _ebbTreeHeight[SMDSAbs_NbElementTypes]; - SMESH_NodeSearcherImpl* _nodeSearcher; - SMDSAbs_ElementType _elementType; - double _tolerance; - bool _outerFacesFound; - set _outerFaces; // empty means "no internal faces at all" + 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, @@ -532,20 +520,26 @@ struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher } 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); - void GetElementsInSphere( const gp_XYZ& center, - const double radius, - 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); @@ -633,7 +627,7 @@ double SMESH_ElementSearcherImpl::getTolerance() while ( nodeIt->more() ) { double dist = n1.Distance( static_cast( nodeIt->next() )); - elemSize = max( dist, elemSize ); + elemSize = std::max( dist, elemSize ); } } _tolerance = 1e-4 * elemSize; @@ -691,10 +685,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)); @@ -736,8 +730,8 @@ 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; @@ -746,7 +740,7 @@ void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerF 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; @@ -791,9 +785,9 @@ 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; @@ -834,13 +828,9 @@ FindElementsByPoint(const gp_Pnt& point, { _ebbTree[_elementType] = new ElementBndBoxTree( *_mesh, type, _meshPartIt, tolerance ); } - else - { - _ebbTree[ type ]->prepare(); - } - vector< const SMDS_MeshElement* > suspectElems; + ElementBndBoxTree::TElemSeq suspectElems; _ebbTree[ type ]->getElementsNearPoint( point, suspectElems ); - vector< const SMDS_MeshElement* >::iterator elem = suspectElems.begin(); + ElementBndBoxTree::TElemSeq::iterator elem = suspectElems.begin(); for ( ; elem != suspectElems.end(); ++elem ) if ( !SMESH_MeshAlgos::IsOut( *elem, point, tolerance )) foundElements.push_back( *elem ); @@ -863,15 +853,15 @@ SMESH_ElementSearcherImpl::FindClosestTo( const gp_Pnt& point, const SMDS_MeshElement* closestElem = 0; _elementType = type; - if ( type == SMDSAbs_Face || type == SMDSAbs_Volume ) + if ( type == SMDSAbs_Face || + type == SMDSAbs_Volume || + type == SMDSAbs_Edge ) { ElementBndBoxTree*& ebbTree = _ebbTree[ type ]; if ( !ebbTree ) ebbTree = new ElementBndBoxTree( *_mesh, type, _meshPartIt ); - else - ebbTree->prepare(); - vector suspectElems; + ElementBndBoxTree::TElemSeq suspectElems; ebbTree->getElementsNearPoint( point, suspectElems ); if ( suspectElems.empty() && ebbTree->maxSize() > 0 ) @@ -885,26 +875,25 @@ SMESH_ElementSearcherImpl::FindClosestTo( const gp_Pnt& point, radius = ebbTree->maxSize() / pow( 2., getTreeHeight()) / 2; while ( suspectElems.empty() ) { - ebbTree->prepare(); ebbTree->getElementsInSphere( point.XYZ(), radius, suspectElems ); radius *= 1.1; } } double minDist = std::numeric_limits::max(); - multimap< double, const SMDS_MeshElement* > dist2face; - vector::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 @@ -956,8 +945,6 @@ TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point) ElementBndBoxTree*& ebbTree = _ebbTree[ SMDSAbs_Face ]; if ( !ebbTree ) ebbTree = new ElementBndBoxTree( *_mesh, _elementType, _meshPartIt ); - else - ebbTree->prepare(); // 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 @@ -965,22 +952,21 @@ TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point) 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 ); - vector suspectFaces; // faces possibly intersecting the line - if ( axis > 0 ) ebbTree->prepare(); + ElementBndBoxTree::TElemSeq suspectFaces; // faces possibly intersecting the line ebbTree->getElementsNearLine( lineAxis, suspectFaces ); // Intersect faces with the line - map< double, TInters > & u2inters = paramOnLine2TInters[ axis ]; - vector::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 @@ -1001,7 +987,7 @@ TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point) double tol = 1e-4 * Sqrt( fNorm.Modulus() ); gp_Pnt intersectionPoint = intersection.Point(1); if ( !SMESH_MeshAlgos::IsOut( *face, intersectionPoint, tol )) - u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm ))); + u2inters.insert( std::make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm ))); } } // Analyse intersections roughly @@ -1025,7 +1011,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 @@ -1039,29 +1025,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() ) { @@ -1110,8 +1096,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; @@ -1164,7 +1150,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 ); } @@ -1179,18 +1165,20 @@ 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 ); - else - ebbTree->prepare(); - ebbTree->getElementsNearLine( line, foundElems ); + ElementBndBoxTree::TElemSeq elems; + ebbTree->getElementsNearLine( line, elems ); + + foundElems.insert( foundElems.end(), elems.begin(), elems.end() ); } //======================================================================= @@ -1199,19 +1187,93 @@ void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1& */ //======================================================================= -void SMESH_ElementSearcherImpl::GetElementsInSphere( const gp_XYZ& center, - const double radius, - SMDSAbs_ElementType type, - vector< const SMDS_MeshElement* >& foundElems) +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 ); - else - ebbTree->prepare(); - ebbTree->getElementsInSphere( center, radius, foundElems ); + 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) +{ + _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(); + double radius = ( box->CornerMax() - box->CornerMin() ).Modulus(); + + ElementBndBoxTree::TElemSeq elems; + ebbTree->getElementsInSphere( p, radius, elems ); + while ( elems.empty() ) + { + radius *= 1.5; + ebbTree->getElementsInSphere( p, radius, elems ); + } + gp_XYZ proj, bestProj; + const SMDS_MeshElement* elem = 0; + double minDist = 2 * radius; + ElementBndBoxTree::TElemSeq::iterator e = elems.begin(); + for ( ; e != elems.end(); ++e ) + { + double d = SMESH_MeshAlgos::GetDistance( *e, p, &proj ); + if ( d < minDist ) + { + bestProj = proj; + elem = *e; + minDist = d; + } + } + if ( closestElem ) *closestElem = elem; + + return bestProj; } //======================================================================= @@ -1229,9 +1291,9 @@ bool SMESH_MeshAlgos::IsOut( const SMDS_MeshElement* element, const gp_Pnt& poin // get ordered nodes - vector< SMESH_TNodeXYZ > xyz; xyz.reserve( element->NbNodes()+1 ); + std::vector< SMESH_TNodeXYZ > xyz; xyz.reserve( element->NbNodes()+1 ); - SMDS_ElemIteratorPtr nodeIt = element->interlacedNodesElemIterator(); + SMDS_NodeIteratorPtr nodeIt = element->interlacedNodesIterator(); for ( int i = 0; nodeIt->more(); ++i ) xyz.push_back( SMESH_TNodeXYZ( nodeIt->next() )); @@ -1294,7 +1356,7 @@ bool SMESH_MeshAlgos::IsOut( const SMDS_MeshElement* element, const gp_Pnt& poin 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 - vector dist( nbNodes + 1); + std::vector dist( nbNodes + 1); for ( i = 0; i < nbNodes; ++i ) { gp_Vec n2p( xyz[i], point ); @@ -1461,17 +1523,19 @@ 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:; } @@ -1487,14 +1551,15 @@ 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; // coordinates of nodes (medium nodes, if any, ignored) typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > TXyzIterator; - vector xyz( TXyzIterator( face->nodesIterator()), TXyzIterator() ); + std::vector xyz( TXyzIterator( face->nodesIterator()), TXyzIterator() ); xyz.resize( face->NbCornerNodes()+1 ); // transformation to get xyz[0] lies on the origin, xyz[1] lies on the Z axis, @@ -1518,7 +1583,7 @@ double SMESH_MeshAlgos::GetDistance( const SMDS_MeshFace* face, trsf.SetTransformation( tgtCS ); // move all the nodes to 2D - vector xy( xyz.size() ); + std::vector xy( xyz.size() ); for ( size_t i = 0;i < xyz.size()-1; ++i ) { gp_XYZ p3d = xyz[i]; @@ -1533,8 +1598,8 @@ 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::set< PointPos > pntPosSet; for ( size_t i = 1; i < xy.size(); ++i ) { PointPos pos = getPointPosition( point2D, &xy[0], i-1 ); @@ -1543,31 +1608,40 @@ double SMESH_MeshAlgos::GetDistance( const SMDS_MeshFace* face, // 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_LEFT: + { + // point is most close to an edge + 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 + // projection of the point on the edge + gp_XYZ proj = xyz[ pos._index ] + u * edge.XYZ(); + if ( closestPnt ) *closestPnt = proj; + return point.Distance( proj ); } - case POS_RIGHT: { + case POS_RIGHT: + { // point is inside the face - double distToFacePlane = tmpPnt.Y(); - // cout << distToFacePlane << ", INSIDE " << endl; - return Abs( distToFacePlane ); + double distToFacePlane = Abs( tmpPnt.Y() ); + if ( closestPnt ) + { + if ( distToFacePlane < std::numeric_limits::min() ) { + *closestPnt = point.XYZ(); + } + else { + tmpPnt.SetY( 0 ); + trsf.Inverted().Transforms( tmpPnt ); + *closestPnt = tmpPnt; + } + } + return distToFacePlane; } - case POS_VERTEX: { + 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(); } default:; @@ -1581,32 +1655,42 @@ double SMESH_MeshAlgos::GetDistance( const SMDS_MeshFace* face, */ //======================================================================= -double SMESH_MeshAlgos::GetDistance( const SMDS_MeshEdge* seg, const gp_Pnt& point ) +double SMESH_MeshAlgos::GetDistance( const SMDS_MeshEdge* seg, + const gp_Pnt& point, + gp_XYZ* closestPnt ) { double dist = Precision::Infinite(); if ( !seg ) return dist; int i = 0, nbNodes = seg->NbNodes(); - vector< SMESH_TNodeXYZ > xyz( nbNodes ); - SMDS_ElemIteratorPtr nodeIt = seg->interlacedNodesElemIterator(); - while ( nodeIt->more() ) - xyz[ i++ ].Set( nodeIt->next() ); + 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 u = ( edge * n1p ) / edge.SquareMagnitude(); // param [0,1] on the edge + double d, u = ( edge * n1p ) / edge.SquareMagnitude(); // param [0,1] on the edge if ( u <= 0. ) { - dist = Min( dist, n1p.SquareMagnitude() ); + if (( d = n1p.SquareMagnitude() ) < dist ) { + dist = d; + if ( closestPnt ) *closestPnt = xyz[i-1]; + } } else if ( u >= 1. ) { - dist = Min( dist, point.SquareDistance( xyz[i] )); + if (( d = point.SquareDistance( xyz[i] )) < dist ) { + dist = d; + if ( closestPnt ) *closestPnt = xyz[i]; + } } else { - gp_XYZ proj = ( 1. - u ) * xyz[i-1] + u * xyz[i]; // projection of the point on the edge - dist = Min( dist, point.SquareDistance( proj )); + 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 ); @@ -1620,7 +1704,9 @@ double SMESH_MeshAlgos::GetDistance( const SMDS_MeshEdge* seg, const gp_Pnt& poi */ //======================================================================= -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(); @@ -1628,6 +1714,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 @@ -1644,23 +1732,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 } //================================================================================ @@ -1691,7 +1790,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; } @@ -1737,7 +1836,7 @@ SMESH_MeshAlgos::FindFaceInSet(const SMDS_MeshNode* n1, if ( !face && elem->IsQuadratic()) { // analysis for quadratic elements using all nodes - 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++ ) { @@ -1748,7 +1847,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; } @@ -1783,7 +1882,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 ); @@ -1795,15 +1894,43 @@ 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 ); +} //======================================================================= /*!