-// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE
+// Copyright (C) 2007-2021 CEA/DEN, EDF R&D, OPEN CASCADE
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
#include <vector>
#include <NCollection_DataMap.hxx>
+#include <Precision.hxx>
#include <gp_Pnt.hxx>
using namespace SMESH_MeshAlgos;
bool HasCloseEdgeWithNode( const BNode* n ) const;
bool IsCloseEdge( const BEdge*, double * u = 0 ) const;
bool operator<(const BNode& other) const { return Node()->GetID() < other.Node()->GetID(); }
+ double SquareDistance(const BNode& e2) const { return ( e2 - *this ).SquareModulus(); }
};
/*!
* \brief Edge of a free border
myNodes[0] = node1->Node();
myNodes[1] = node2->Node();
myFace = face;
- setId( ID ); // mesh element ID
+ setID( ID ); // mesh element ID
}
bool IsInGroup() const
{
if ( myID < 0 )
{
myID = id;
- if ( myNext )
- myNext->SetID( id + 1 );
+
+ for ( BEdge* be = myNext; be && be->myID < 0; be = be->myNext )
+ {
+ be->myID = ++id;
+ }
}
}
+ //================================================================================
+ /*!
+ * \brief Checks if a point is closer to this BEdge than tol
+ */
+ //================================================================================
+
bool IsOut( const gp_XYZ& point, const double tol, double& u ) const
{
gp_XYZ me = *myBNode2 - *myBNode1;
double dist2 = ( point - proj ).SquareModulus();
return ( dist2 > tol * tol );
}
+ //================================================================================
+ /*!
+ * \brief Checks if two BEdges can be considered as overlapping
+ */
+ //================================================================================
+
bool IsOverlappingProjection( const BEdge* toE, const double u, bool is1st ) const
{
// is1st shows which end of toE is projected on this at u
return Abs( u - u2 ) > eps;
return false;
}
+ //================================================================================
+ /*!
+ * \brief Finds all neighbor BEdge's having the same close borders
+ */
+ //================================================================================
+
bool GetRangeOfSameCloseBorders(BEdge* eRange[2], const std::set< int >& bordIDs)
{
if ( this->myCloseBorders != bordIDs )
}
}; // class BEdge
+ //================================================================================
+ /*!
+ * \brief Checks if all border parts include the whole closed border, and if so
+ * returns \c true and choose starting BEdge's with most coincident nodes
+ */
+ //================================================================================
+
+ bool chooseStartOfClosedBorders( std::vector< BEdge* >& ranges ) // PAL23078#c21002
+ {
+ bool allClosed = true;
+ for ( size_t iR = 1; iR < ranges.size() && allClosed; iR += 2 )
+ allClosed = ( ranges[ iR-1 ]->myPrev == ranges[ iR ] );
+ if ( !allClosed )
+ return allClosed;
+
+ double u, minDiff = Precision::Infinite();
+ std::vector< BEdge* > start( ranges.size() / 2 );
+ BEdge* range0 = start[0] = ranges[0];
+ do
+ {
+ double maxDiffU = 0;
+ double maxDiff = 0;
+ for ( size_t iR = 3; iR < ranges.size(); iR += 2 )
+ {
+ int borderID = ranges[iR]->myBorderID;
+ if ( BEdge* e = start[0]->myBNode1->GetCloseEdgeOfBorder( borderID, & u ))
+ {
+ start[ iR / 2 ] = e;
+ double diffU = Min( Abs( u ), Abs( 1.-u ));
+ double diff = e->myBNode1->SquareDistance( *e->myBNode2 ) * diffU * diffU;
+ maxDiffU = Max( diffU, maxDiffU );
+ maxDiff = Max( diff, maxDiff );
+ }
+ }
+ if ( maxDiff < minDiff )
+ {
+ minDiff = maxDiff;
+ for ( size_t iR = 1; iR < ranges.size(); iR += 2 )
+ {
+ ranges[ iR-1 ] = start[ iR/2 ];
+ ranges[ iR ] = ranges[ iR-1]->myPrev;
+ }
+ }
+ if ( maxDiffU < 1e-6 )
+ break;
+ start[0] = start[0]->myNext;
+ }
+ while ( start[0] != range0 );
+
+ return allClosed;
+ }
+
+ //================================================================================
+ /*!
+ * \brief Tries to include neighbor BEdge's into a border part
+ */
+ //================================================================================
+
void extendPart( BEdge* & e1, BEdge* & e2, const std::set< int >& bordIDs, int groupID )
{
if (( e1->myPrev == e2 ) ||
}
}
+ //================================================================================
+ /*!
+ * \brief Connect BEdge's incident at this node
+ */
+ //================================================================================
+
void BNode::AddLinked( BEdge* e ) const
{
myLinkedEdges.reserve(2);
if ( ranges.size() > 2 )
{
- for ( size_t iR = 1; iR < ranges.size(); iR += 2 )
- extendPart( ranges[ iR-1 ], ranges[ iR ], be1st->myCloseBorders, groupID );
+ if ( !chooseStartOfClosedBorders( ranges ))
+ for ( size_t iR = 1; iR < ranges.size(); iR += 2 )
+ extendPart( ranges[ iR-1 ], ranges[ iR ], be1st->myCloseBorders, groupID );
// fill in a group
beRange[0] = ranges[0];
} // SMESH_MeshAlgos::FindCoincidentFreeBorders()
+//================================================================================
+/*
+ * Returns all TFreeBorder's. Optionally check if the mesh is manifold
+ * and if faces are correctly oriented.
+ */
+//================================================================================
+
+void SMESH_MeshAlgos::FindFreeBorders(SMDS_Mesh& theMesh,
+ TFreeBorderVec & theFoundFreeBordes,
+ const bool theClosedOnly,
+ bool* theIsManifold,
+ bool* theIsGoodOri)
+{
+ bool isManifold = true;
+
+ // find free links
+ typedef NCollection_DataMap<SMESH_TLink, const SMDS_MeshElement*, SMESH_TLink > TLink2FaceMap;
+ TLink2FaceMap linkMap;
+ int nbSharedLinks = 0;
+ SMDS_FaceIteratorPtr faceIt = theMesh.facesIterator();
+ while ( faceIt->more() )
+ {
+ const SMDS_MeshElement* face = faceIt->next();
+ if ( !face ) continue;
+
+ const SMDS_MeshNode* n0 = face->GetNode( face->NbNodes() - 1 );
+ SMDS_NodeIteratorPtr nodeIt = face->interlacedNodesIterator();
+ while ( nodeIt->more() )
+ {
+ const SMDS_MeshNode* n1 = nodeIt->next();
+ SMESH_TLink link( n0, n1 );
+ if ( const SMDS_MeshElement** faceInMap = linkMap.ChangeSeek( link ))
+ {
+ if ( *faceInMap )
+ {
+ if ( theIsGoodOri && *theIsGoodOri && !IsRightOrder( *faceInMap, n1, n0 ))
+ *theIsGoodOri = false;
+ }
+ else
+ {
+ isManifold = false;
+ }
+ nbSharedLinks += bool( *faceInMap );
+ *faceInMap = 0;
+ }
+ else
+ {
+ linkMap.Bind( link, face );
+ }
+ n0 = n1;
+ }
+ }
+ if ( theIsManifold )
+ *theIsManifold = isManifold;
+
+ if ( linkMap.Extent() == nbSharedLinks )
+ return;
+
+ // form free borders
+ std::set < BNode > bNodes;
+ std::vector< BEdge > bEdges( linkMap.Extent() - nbSharedLinks );
+
+ TLink2FaceMap::Iterator linkIt( linkMap );
+ for ( int iEdge = 0; linkIt.More(); linkIt.Next() )
+ {
+ if ( !linkIt.Value() ) continue;
+ const SMESH_TLink & link = linkIt.Key();
+ std::set< BNode >::iterator n1 = bNodes.insert( BNode( link.node1() )).first;
+ std::set< BNode >::iterator n2 = bNodes.insert( BNode( link.node2() )).first;
+ bEdges[ iEdge ].Set( &*n1, &*n2, linkIt.Value(), iEdge+1 );
+ n1->AddLinked( & bEdges[ iEdge ] );
+ n2->AddLinked( & bEdges[ iEdge ] );
+ ++iEdge;
+ }
+ linkMap.Clear();
+
+ // assign IDs to borders
+ std::vector< BEdge* > borders; // 1st of connected (via myPrev and myNext) edges
+ std::set< BNode >::iterator bn = bNodes.begin();
+ for ( ; bn != bNodes.end(); ++bn )
+ {
+ for ( size_t i = 0; i < bn->myLinkedEdges.size(); ++i )
+ {
+ if ( bn->myLinkedEdges[i]->myBorderID < 0 )
+ {
+ BEdge* be = bn->myLinkedEdges[i];
+ int borderID = borders.size();
+ borders.push_back( be );
+ for ( ; be && be->myBorderID < 0; be = be->myNext )
+ {
+ be->myBorderID = borderID;
+ be->Orient();
+ }
+ bool isClosed = ( be == bn->myLinkedEdges[i] );
+ if ( !isClosed && theClosedOnly )
+ {
+ borders.pop_back();
+ continue;
+ }
+ be = bn->myLinkedEdges[i]->myPrev;
+ for ( ; be && be->myBorderID < 0; be = be->myPrev )
+ {
+ be->myBorderID = borderID;
+ be->Orient();
+ }
+ if ( !isClosed )
+ while ( borders.back()->myPrev )
+ borders.back() = borders.back()->myPrev;
+ }
+ }
+ }
+ theFoundFreeBordes.resize( borders.size() );
+ for ( size_t i = 0; i < borders.size(); ++i )
+ {
+ TFreeBorder & bordNodes = theFoundFreeBordes[ i ];
+ BEdge* be = borders[i];
+
+ size_t cnt = 1;
+ for ( be = be->myNext; be && be != borders[i]; be = be->myNext )
+ ++cnt;
+ bordNodes.resize( cnt + 1 );
+
+ BEdge* beLast = 0;
+ for ( be = borders[i], cnt = 0;
+ be && cnt < bordNodes.size()-1;
+ be = be->myNext, ++cnt )
+ {
+ bordNodes[ cnt ] = be->myBNode1->Node();
+ beLast = be;
+ }
+ if ( beLast )
+ bordNodes.back() = beLast->myBNode2->Node();
+ }
+}