1 // Copyright (C) 2007-2016 CEA/DEN, EDF R&D, OPEN CASCADE
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 // Lesser General Public License for more details.
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
19 // File : SMESH_FreeBorders.cxx
20 // Created : Tue Sep 8 17:08:39 2015
21 // Author : Edward AGAPOV (eap)
23 //================================================================================
24 // Implementation of SMESH_MeshAlgos::FindCoincidentFreeBorders()
25 //================================================================================
27 #include "SMESH_MeshAlgos.hxx"
29 #include "SMDS_LinearEdge.hxx"
30 #include "SMDS_Mesh.hxx"
31 #include "SMDS_SetIterator.hxx"
38 #include <NCollection_DataMap.hxx>
39 #include <Precision.hxx>
42 using namespace SMESH_MeshAlgos;
49 * \brief Node on a free border
51 struct BNode : public SMESH_TNodeXYZ
53 mutable std::vector< BEdge* > myLinkedEdges;
54 mutable std::vector< std::pair < BEdge*, double > > myCloseEdges; // edge & U
56 BNode(const SMDS_MeshNode * node): SMESH_TNodeXYZ( node ) {}
57 const SMDS_MeshNode * Node() const { return _node; }
58 void AddLinked( BEdge* e ) const;
59 void AddClose ( const BEdge* e, double u ) const;
60 BEdge* GetCloseEdge( size_t i ) const { return myCloseEdges[i].first; }
61 double GetCloseU( size_t i ) const { return myCloseEdges[i].second; }
62 BEdge* GetCloseEdgeOfBorder( int borderID, double * u = 0 ) const;
63 bool HasCloseEdgeWithNode( const BNode* n ) const;
64 bool IsCloseEdge( const BEdge*, double * u = 0 ) const;
65 bool operator<(const BNode& other) const { return Node()->GetID() < other.Node()->GetID(); }
66 double SquareDistance(const BNode& e2) const { return ( e2 - *this ).SquareModulus(); }
69 * \brief Edge of a free border
71 struct BEdge : public SMDS_LinearEdge
73 const BNode* myBNode1;
74 const BNode* myBNode2;
76 int myID; // within a border
79 const SMDS_MeshElement* myFace;
80 std::set< int > myCloseBorders;
83 BEdge():SMDS_LinearEdge( 0, 0 ), myBorderID(-1), myID(-1), myPrev(0), myNext(0), myInGroup(-1) {}
85 void Set( const BNode * node1,
87 const SMDS_MeshElement* face,
92 myNodes[0] = node1->Node();
93 myNodes[1] = node2->Node();
95 setId( ID ); // mesh element ID
97 bool IsInGroup() const
99 return myInGroup >= 0;
101 bool Contains( const BNode* n ) const
103 return ( n == myBNode1 || n == myBNode2 );
105 void AddLinked( BEdge* e )
107 if ( e->Contains( myBNode1 )) myPrev = e;
110 void RemoveLinked( BEdge* e )
112 if ( myPrev == e ) myPrev = 0;
113 if ( myNext == e ) myNext = 0;
117 std::swap( myBNode1, myBNode2 );
118 myNodes[0] = myBNode1->Node();
119 myNodes[1] = myBNode2->Node();
123 if (( myPrev && !myPrev->Contains( myBNode1 )) ||
124 ( myNext && !myNext->Contains( myBNode2 )))
125 std::swap( myPrev, myNext );
126 if ( myPrev && myPrev->myBNode2 != myBNode1 ) myPrev->Reverse();
127 if ( myNext && myNext->myBNode1 != myBNode2 ) myNext->Reverse();
135 myNext->SetID( id + 1 );
138 //================================================================================
140 * \brief Checks if a point is closer to this BEdge than tol
142 //================================================================================
144 bool IsOut( const gp_XYZ& point, const double tol, double& u ) const
146 gp_XYZ me = *myBNode2 - *myBNode1;
147 gp_XYZ n1p = point - *myBNode1;
148 u = ( me * n1p ) / me.SquareModulus(); // param [0,1] on this
149 if ( u < 0. ) return ( n1p.SquareModulus() > tol * tol );
150 if ( u > 1. ) return ( ( point - *myBNode2 ).SquareModulus() > tol * tol );
152 gp_XYZ proj = ( 1. - u ) * *myBNode1 + u * *myBNode2; // projection of the point on this
153 double dist2 = ( point - proj ).SquareModulus();
154 return ( dist2 > tol * tol );
156 //================================================================================
158 * \brief Checks if two BEdges can be considered as overlapping
160 //================================================================================
162 bool IsOverlappingProjection( const BEdge* toE, const double u, bool is1st ) const
164 // is1st shows which end of toE is projected on this at u
166 const double eps = 0.1;
167 if ( myBNode1->IsCloseEdge( toE, &u2 ) ||
168 myBNode2->IsCloseEdge( toE, &u2 ))
169 return (( 0 < u2 && u2 < 1 ) && // u2 is proj param of myBNode's on toE
170 ( Abs( u2 - int( !is1st )) > eps ));
172 const BNode* n = is1st ? toE->myBNode2 : toE->myBNode1;
173 if ( this == n->GetCloseEdgeOfBorder( this->myBorderID, &u2 ))
174 return Abs( u - u2 ) > eps;
177 //================================================================================
179 * \brief Finds all neighbor BEdge's having the same close borders
181 //================================================================================
183 bool GetRangeOfSameCloseBorders(BEdge* eRange[2], const std::set< int >& bordIDs)
185 if ( this->myCloseBorders != bordIDs )
188 if ( bordIDs.size() == 1 && bordIDs.count( myBorderID )) // border close to self
192 while ( eRange[0]->myBNode1->GetCloseEdgeOfBorder( myBorderID, &u ))
194 if ( eRange[0]->myPrev == this || u < 0 || u > 1 )
196 eRange[0] = eRange[0]->myPrev;
199 while ( eRange[1]->myBNode2->GetCloseEdgeOfBorder( myBorderID, &u ))
201 if ( eRange[1]->myNext == this || u < 0 || u > 1 )
203 eRange[1] = eRange[1]->myNext;
209 while ( eRange[0]->myPrev && eRange[0]->myPrev->myCloseBorders == bordIDs )
211 if ( eRange[0]->myPrev == this )
213 eRange[0] = eRange[0]->myPrev;
217 if ( eRange[0]->myPrev != this ) // not closed border
218 while ( eRange[1]->myNext && eRange[1]->myNext->myCloseBorders == bordIDs )
220 if ( eRange[1]->myNext == this )
222 eRange[1] = eRange[1]->myNext;
226 if ( eRange[0] == eRange[1] )
228 std::set<int>::iterator closeBord = eRange[0]->myCloseBorders.begin();
229 for ( ; closeBord != eRange[0]->myCloseBorders.end(); ++closeBord )
231 if ( BEdge* be = eRange[0]->myBNode1->GetCloseEdgeOfBorder( *closeBord ))
232 if ( be->myCloseBorders == eRange[0]->myCloseBorders )
234 if ( BEdge* be = eRange[0]->myBNode2->GetCloseEdgeOfBorder( *closeBord ))
235 if ( be->myCloseBorders == eRange[0]->myCloseBorders )
244 //================================================================================
246 * \brief Checks if all border parts include the whole closed border, and if so
247 * returns \c true and choose starting BEdge's with most coincident nodes
249 //================================================================================
251 bool chooseStartOfClosedBorders( std::vector< BEdge* >& ranges ) // PAL23078#c21002
253 bool allClosed = true;
254 for ( size_t iR = 1; iR < ranges.size() && allClosed; iR += 2 )
255 allClosed = ( ranges[ iR-1 ]->myPrev == ranges[ iR ] );
259 double u, minDiff = Precision::Infinite();
260 std::vector< BEdge* > start( ranges.size() / 2 );
261 BEdge* range0 = start[0] = ranges[0];
266 for ( size_t iR = 3; iR < ranges.size(); iR += 2 )
268 int borderID = ranges[iR]->myBorderID;
269 if ( BEdge* e = start[0]->myBNode1->GetCloseEdgeOfBorder( borderID, & u ))
272 double diffU = Min( Abs( u ), Abs( 1.-u ));
273 double diff = e->myBNode1->SquareDistance( *e->myBNode2 ) * diffU * diffU;
274 maxDiffU = Max( diffU, maxDiffU );
275 maxDiff = Max( diff, maxDiff );
278 if ( maxDiff < minDiff )
281 for ( size_t iR = 1; iR < ranges.size(); iR += 2 )
283 ranges[ iR-1 ] = start[ iR/2 ];
284 ranges[ iR ] = ranges[ iR-1]->myPrev;
287 if ( maxDiffU < 1e-6 )
289 start[0] = start[0]->myNext;
291 while ( start[0] != range0 );
296 //================================================================================
298 * \brief Tries to include neighbor BEdge's into a border part
300 //================================================================================
302 void extendPart( BEdge* & e1, BEdge* & e2, const std::set< int >& bordIDs, int groupID )
304 if (( e1->myPrev == e2 ) ||
305 ( e1 == e2 && e1->myPrev && e1->myPrev->myInGroup == groupID ))
306 return; // full free border already
310 std::set<int>::const_iterator bord;
313 for ( bord = bordIDs.begin(); bord != bordIDs.end(); ++bord )
314 if ((( be = e1->myBNode1->GetCloseEdgeOfBorder( *bord, &u ))) &&
315 ( be->myInGroup == groupID ) &&
316 ( 0 < u && u < 1 ) &&
317 ( be->IsOverlappingProjection( e1->myPrev, u, false )))
322 if ( bord == bordIDs.end() && // not extended
323 e1->myBNode1->HasCloseEdgeWithNode( e1->myPrev->myBNode1 ))
327 e1->myInGroup = groupID;
331 for ( bord = bordIDs.begin(); bord != bordIDs.end(); ++bord )
332 if ((( be = e2->myBNode2->GetCloseEdgeOfBorder( *bord, &u ))) &&
333 ( be->myInGroup == groupID ) &&
334 ( 0 < u && u < 1 ) &&
335 ( be->IsOverlappingProjection( e2->myNext, u, true )))
340 if ( bord == bordIDs.end() && // not extended
341 e2->myBNode2->HasCloseEdgeWithNode( e2->myNext->myBNode2 ))
345 e2->myInGroup = groupID;
349 //================================================================================
351 * \brief Connect BEdge's incident at this node
353 //================================================================================
355 void BNode::AddLinked( BEdge* e ) const
357 myLinkedEdges.reserve(2);
358 myLinkedEdges.push_back( e );
359 if ( myLinkedEdges.size() < 2 ) return;
361 if ( myLinkedEdges.size() == 2 )
363 myLinkedEdges[0]->AddLinked( myLinkedEdges[1] );
364 myLinkedEdges[1]->AddLinked( myLinkedEdges[0] );
368 for ( size_t i = 0; i < myLinkedEdges.size(); ++i )
369 for ( size_t j = 0; j < myLinkedEdges.size(); ++j )
371 myLinkedEdges[i]->RemoveLinked( myLinkedEdges[j] );
374 void BNode::AddClose ( const BEdge* e, double u ) const
376 if ( ! e->Contains( this ))
377 myCloseEdges.push_back( std::make_pair( const_cast< BEdge* >( e ), u ));
379 BEdge* BNode::GetCloseEdgeOfBorder( int borderID, double * uPtr ) const
383 for ( size_t i = 0; i < myCloseEdges.size(); ++i )
384 if ( borderID == GetCloseEdge( i )->myBorderID )
386 if ( e && Abs( u - 0.5 ) < Abs( GetCloseU( i ) - 0.5 ))
389 e = GetCloseEdge ( i );
391 if ( uPtr ) *uPtr = u;
394 bool BNode::HasCloseEdgeWithNode( const BNode* n ) const
396 for ( size_t i = 0; i < myCloseEdges.size(); ++i )
397 if ( GetCloseEdge( i )->Contains( n ) &&
398 0 < GetCloseU( i ) && GetCloseU( i ) < 1 )
402 bool BNode::IsCloseEdge( const BEdge* e, double * uPtr ) const
404 for ( size_t i = 0; i < myCloseEdges.size(); ++i )
405 if ( e == GetCloseEdge( i ) )
407 if ( uPtr ) *uPtr = GetCloseU( i );
413 /// Accessor to SMDS_MeshElement* inherited by BEdge
416 static const SMDS_MeshElement* value( std::vector< BEdge >::const_iterator it)
421 /// Iterator over a vector of BEdge's
422 static SMDS_ElemIteratorPtr getElemIterator( const std::vector< BEdge > & bedges )
424 typedef SMDS_SetIterator
425 < const SMDS_MeshElement*, std::vector< BEdge >::const_iterator, ElemAcess > BEIter;
426 return SMDS_ElemIteratorPtr( new BEIter( bedges.begin(), bedges.end() ));
431 //================================================================================
433 * Returns groups of TFreeBorder's coincident within the given tolerance.
434 * If the tolerance <= 0.0 then one tenth of an average size of elements adjacent
435 * to free borders being compared is used.
437 //================================================================================
439 void SMESH_MeshAlgos::FindCoincidentFreeBorders(SMDS_Mesh& mesh,
441 CoincidentFreeBorders & foundFreeBordes)
444 typedef NCollection_DataMap<SMESH_TLink, const SMDS_MeshElement*, SMESH_TLink > TLink2FaceMap;
445 TLink2FaceMap linkMap;
446 int nbSharedLinks = 0;
447 SMDS_FaceIteratorPtr faceIt = mesh.facesIterator();
448 while ( faceIt->more() )
450 const SMDS_MeshElement* face = faceIt->next();
451 if ( !face ) continue;
453 const SMDS_MeshNode* n0 = face->GetNode( face->NbNodes() - 1 );
454 SMDS_NodeIteratorPtr nodeIt = face->interlacedNodesIterator();
455 while ( nodeIt->more() )
457 const SMDS_MeshNode* n1 = nodeIt->next();
458 SMESH_TLink link( n0, n1 );
459 if ( const SMDS_MeshElement** faceInMap = linkMap.ChangeSeek( link ))
461 nbSharedLinks += bool( *faceInMap );
466 linkMap.Bind( link, face );
471 if ( linkMap.Extent() == nbSharedLinks )
475 std::set < BNode > bNodes;
476 std::vector< BEdge > bEdges( linkMap.Extent() - nbSharedLinks );
478 TLink2FaceMap::Iterator linkIt( linkMap );
479 for ( int iEdge = 0; linkIt.More(); linkIt.Next() )
481 if ( !linkIt.Value() ) continue;
482 const SMESH_TLink & link = linkIt.Key();
483 std::set< BNode >::iterator n1 = bNodes.insert( BNode( link.node1() )).first;
484 std::set< BNode >::iterator n2 = bNodes.insert( BNode( link.node2() )).first;
485 bEdges[ iEdge ].Set( &*n1, &*n2, linkIt.Value(), iEdge+1 );
486 n1->AddLinked( & bEdges[ iEdge ] );
487 n2->AddLinked( & bEdges[ iEdge ] );
492 // assign IDs to borders
493 std::vector< BEdge* > borders; // 1st of connected (via myPrev and myNext) edges
494 std::set< BNode >::iterator bn = bNodes.begin();
495 for ( ; bn != bNodes.end(); ++bn )
497 for ( size_t i = 0; i < bn->myLinkedEdges.size(); ++i )
499 if ( bn->myLinkedEdges[i]->myBorderID < 0 )
501 BEdge* be = bn->myLinkedEdges[i];
502 int borderID = borders.size();
503 borders.push_back( be );
504 for ( ; be && be->myBorderID < 0; be = be->myNext )
506 be->myBorderID = borderID;
509 bool isClosed = ( be == bn->myLinkedEdges[i] );
510 be = bn->myLinkedEdges[i]->myPrev;
511 for ( ; be && be->myBorderID < 0; be = be->myPrev )
513 be->myBorderID = borderID;
517 while ( borders.back()->myPrev )
518 borders.back() = borders.back()->myPrev;
520 borders.back()->SetID( 0 ); // set IDs to all edges of the border
525 // compute tolerance of each border
526 double maxTolerance = tolerance;
527 std::vector< double > bordToler( borders.size(), tolerance );
528 if ( maxTolerance < std::numeric_limits< double >::min() )
530 // no tolerance provided by the user; compute tolerance of each border
531 // as one tenth of an average size of faces adjacent to a border
532 for ( size_t i = 0; i < borders.size(); ++i )
534 double avgFaceSize = 0;
536 BEdge* be = borders[ i ];
538 double facePerimeter = 0;
539 gp_Pnt p0 = SMESH_TNodeXYZ( be->myFace->GetNode( be->myFace->NbNodes() - 1 ));
540 SMDS_NodeIteratorPtr nodeIt = be->myFace->interlacedNodesIterator();
541 while ( nodeIt->more() )
543 gp_Pnt p1 = SMESH_TNodeXYZ( nodeIt->next() );
544 facePerimeter += p0.Distance( p1 );
547 avgFaceSize += ( facePerimeter / be->myFace->NbCornerNodes() );
552 while ( be && be != borders[i] );
554 bordToler[ i ] = 0.1 * avgFaceSize / nbFaces;
555 maxTolerance = Max( maxTolerance, bordToler[ i ]);
559 // for every border node find close border edges
560 SMESH_ElementSearcher* searcher =
561 GetElementSearcher( mesh, getElemIterator( bEdges ), maxTolerance );
562 SMESHUtils::Deleter< SMESH_ElementSearcher > searcherDeleter( searcher );
563 std::vector< const SMDS_MeshElement* > candidateEdges;
564 for ( bn = bNodes.begin(); bn != bNodes.end(); ++bn )
566 searcher->FindElementsByPoint( *bn, SMDSAbs_Edge, candidateEdges );
567 if ( candidateEdges.size() <= bn->myLinkedEdges.size() )
570 double nodeTol = 0, u;
571 for ( size_t i = 0; i < bn->myLinkedEdges.size(); ++i )
572 nodeTol = Max( nodeTol, bordToler[ bn->myLinkedEdges[ i ]->myBorderID ]);
574 for ( size_t i = 0; i < candidateEdges.size(); ++i )
576 const BEdge* be = static_cast< const BEdge* >( candidateEdges[ i ]);
577 double tol = Max( nodeTol, bordToler[ be->myBorderID ]);
578 if ( !be->IsOut( *bn, tol, u ))
579 bn->AddClose( be, u );
583 // for every border edge find close borders
585 std::vector< BEdge* > closeEdges;
586 for ( size_t i = 0; i < bEdges.size(); ++i )
588 BEdge& be = bEdges[i];
589 if ( be.myBNode1->myCloseEdges.empty() ||
590 be.myBNode2->myCloseEdges.empty() )
594 for ( size_t iE1 = 0; iE1 < be.myBNode1->myCloseEdges.size(); ++iE1 )
596 // find edges of the same border close to both nodes of the edge
597 BEdge* closeE1 = be.myBNode1->GetCloseEdge( iE1 );
598 BEdge* closeE2 = be.myBNode2->GetCloseEdgeOfBorder( closeE1->myBorderID );
601 // check that edges connecting closeE1 and closeE2 (if any) are also close to 'be'
602 if ( closeE1 != closeE2 )
605 for ( int j = 0; j < 2; ++j ) // move closeE1 -> closeE2 or inversely
609 coincide = ( ce->myBNode2->GetCloseEdgeOfBorder( be.myBorderID ));
611 } while ( coincide && ce && ce != closeE2 );
613 if ( coincide && ce == closeE2 )
616 std::swap( closeE1, closeE2 );
621 closeEdges.push_back( closeE1 );
622 closeEdges.push_back( closeE2 );
626 closeEdges.push_back( closeE1 );
628 be.myCloseBorders.insert( closeE1->myBorderID );
630 if ( !closeEdges.empty() )
632 be.myCloseBorders.insert( be.myBorderID );
633 // for ( size_t iB = 0; iB < closeEdges.size(); ++iB )
634 // closeEdges[ iB ]->myCloseBorders.insert( be.myCloseBorders.begin(),
635 // be.myCloseBorders.end() );
639 // Fill in CoincidentFreeBorders
641 // save nodes of free borders
642 foundFreeBordes._borders.resize( borders.size() );
643 for ( size_t i = 0; i < borders.size(); ++i )
645 BEdge* be = borders[i];
646 foundFreeBordes._borders[i].push_back( be->myBNode1->Node() );
648 foundFreeBordes._borders[i].push_back( be->myBNode2->Node() );
651 while ( be && be != borders[i] );
654 // form groups of coincident parts of free borders
656 TFreeBorderPart part;
657 TCoincidentGroup group;
658 std::vector< BEdge* > ranges; // couples of edges delimiting parts
659 BEdge* be = 0; // a current edge
660 int skipGroup = bEdges.size(); // a group ID used to avoid repeating treatment of edges
662 for ( int i = 0, nbBords = borders.size(); i < nbBords; i += bool(!be) )
667 // look for an edge close to other borders
669 if ( !be->IsInGroup() && !be->myCloseBorders.empty() )
672 } while ( be && be != borders[i] );
674 if ( !be || be->IsInGroup() || be->myCloseBorders.empty() )
677 continue; // all edges of a border are treated or non-coincident
682 // look for the 1st and last edge of a coincident group
684 if ( !be->GetRangeOfSameCloseBorders( beRange, be->myCloseBorders ))
686 be->myInGroup = skipGroup;
691 ranges.push_back( beRange[0] );
692 ranges.push_back( beRange[1] );
694 int groupID = foundFreeBordes._coincidentGroups.size();
696 be->myInGroup = groupID;
697 while ( be != beRange[1] )
699 be->myInGroup = groupID;
702 beRange[1]->myInGroup = groupID;
704 // get starting edge of each close border
707 if ( be->myCloseBorders.empty() )
708 be = beRange[0]->myNext;
709 std::set<int>::iterator closeBord = be->myCloseBorders.begin();
710 for ( ; closeBord != be->myCloseBorders.end(); ++closeBord )
711 if ( BEdge* e = be->myBNode2->GetCloseEdgeOfBorder( *closeBord ))
712 closeEdges.push_back( e );
714 for ( size_t iE = 0; iE < closeEdges.size(); ++iE )
715 if ( be->myCloseBorders != closeEdges[iE]->myCloseBorders )
717 closeBord = closeEdges[iE]->myCloseBorders.begin();
718 for ( ; closeBord != closeEdges[iE]->myCloseBorders.end(); ++closeBord )
719 if ( !be->myCloseBorders.count( *closeBord ))
720 if ( BEdge* e = closeEdges[iE]->myBNode2->GetCloseEdgeOfBorder( *closeBord ))
721 if ( std::find( closeEdges.begin(), closeEdges.end(), e ) == closeEdges.end() )
722 closeEdges.push_back( e );
725 // add parts of other borders
727 BEdge* be1st = beRange[0];
728 for ( size_t iE = 0; iE < closeEdges.size(); ++iE )
730 be = closeEdges[ iE ];
733 bool ok = be->GetRangeOfSameCloseBorders( beRange, be->myCloseBorders );
734 // if ( !ok && be->myPrev )
735 // ok = be->myPrev->GetRangeOfSameCloseBorders( beRange, be1st->myCloseBorders );
736 // if ( !ok && be->myNext )
737 // ok = be->myNext->GetRangeOfSameCloseBorders( beRange, be1st->myCloseBorders );
743 ranges.push_back( beRange[0] );
744 ranges.push_back( beRange[1] );
746 be->myInGroup = groupID;
747 while ( be != beRange[1] )
749 be->myInGroup = groupID;
752 beRange[1]->myInGroup = groupID;
755 if ( ranges.size() > 2 )
757 if ( !chooseStartOfClosedBorders( ranges ))
758 for ( size_t iR = 1; iR < ranges.size(); iR += 2 )
759 extendPart( ranges[ iR-1 ], ranges[ iR ], be1st->myCloseBorders, groupID );
762 beRange[0] = ranges[0];
763 beRange[1] = ranges[1];
766 part._node1 = beRange[0]->myID;
767 part._node2 = beRange[0]->myID + 1;
768 part._nodeLast = beRange[1]->myID + 1;
769 group.push_back( part );
772 for ( size_t iR = 3; iR < ranges.size(); iR += 2 )
774 beRange[0] = ranges[iR-1];
775 beRange[1] = ranges[iR-0];
777 // find out mutual orientation of borders
779 be1st ->IsOut( *beRange[ 0 ]->myBNode1, maxTolerance, u1 );
780 beRange[ 0 ]->IsOut( *be1st->myBNode1, maxTolerance, u2 );
781 bool reverse = (( u1 < 0 || u1 > 1 ) && ( u2 < 0 || u2 > 1 ));
784 part._border = beRange[0]->myBorderID;
786 part._node1 = beRange[1]->myID + 1;
787 part._node2 = beRange[1]->myID;
788 part._nodeLast = beRange[0]->myID;
791 part._node1 = beRange[0]->myID;
792 part._node2 = beRange[0]->myID + 1;
793 part._nodeLast = beRange[1]->myID + 1;
795 // if ( group[0]._node2 != part._node2 )
796 group.push_back( part );
798 //if ( group.size() > 1 )
799 foundFreeBordes._coincidentGroups.push_back( group );
803 beRange[0] = ranges[0];
804 beRange[1] = ranges[1];
807 be->myInGroup = skipGroup;
808 while ( be != beRange[1] )
810 be->myInGroup = skipGroup;
813 beRange[1]->myInGroup = skipGroup;
818 } // loop on free borders
822 } // SMESH_MeshAlgos::FindCoincidentFreeBorders()