+//================================================================================
+
+const SMESH_HypoFilter*
+SMESH_Algo::GetCompatibleHypoFilter(const bool ignoreAuxiliary) const
+{
+ if ( !_compatibleHypothesis.empty() )
+ {
+ if ( !_compatibleAllHypFilter )
+ {
+ SMESH_HypoFilter* filter = new SMESH_HypoFilter();
+ filter->Init( filter->HasName( _compatibleHypothesis[0] ));
+ for ( size_t i = 1; i < _compatibleHypothesis.size(); ++i )
+ filter->Or( filter->HasName( _compatibleHypothesis[ i ] ));
+
+ SMESH_HypoFilter* filterNoAux = new SMESH_HypoFilter( filter );
+ filterNoAux->AndNot( filterNoAux->IsAuxiliary() );
+
+ // _compatibleNoAuxHypFilter will detele _compatibleAllHypFilter!!!
+ SMESH_Algo* me = const_cast< SMESH_Algo* >( this );
+ me->_compatibleAllHypFilter = filter;
+ me->_compatibleNoAuxHypFilter = filterNoAux;
+ }
+ return ignoreAuxiliary ? _compatibleNoAuxHypFilter : _compatibleAllHypFilter;
+ }
+ return 0;
+}
+
+//================================================================================
+/*!
+ * \brief Return continuity of two edges
+ * \param E1 - the 1st edge
+ * \param E2 - the 2nd edge
+ * \retval GeomAbs_Shape - regularity at the junction between E1 and E2
+ */
+//================================================================================
+
+GeomAbs_Shape SMESH_Algo::Continuity(const TopoDS_Edge& theE1,
+ const TopoDS_Edge& theE2)
+{
+ // avoid pb with internal edges
+ TopoDS_Edge E1 = theE1, E2 = theE2;
+ if (E1.Orientation() > TopAbs_REVERSED) // INTERNAL
+ E1.Orientation( TopAbs_FORWARD );
+ if (E2.Orientation() > TopAbs_REVERSED) // INTERNAL
+ E2.Orientation( TopAbs_FORWARD );
+
+ TopoDS_Vertex V, VV1[2], VV2[2];
+ TopExp::Vertices( E1, VV1[0], VV1[1], true );
+ TopExp::Vertices( E2, VV2[0], VV2[1], true );
+ if ( VV1[1].IsSame( VV2[0] )) { V = VV1[1]; }
+ else if ( VV1[0].IsSame( VV2[1] )) { V = VV1[0]; }
+ else if ( VV1[1].IsSame( VV2[1] )) { V = VV1[1]; E1.Reverse(); }
+ else if ( VV1[0].IsSame( VV2[0] )) { V = VV1[0]; E1.Reverse(); }
+ else { return GeomAbs_C0; }
+
+ Standard_Real u1 = BRep_Tool::Parameter( V, E1 );
+ Standard_Real u2 = BRep_Tool::Parameter( V, E2 );
+ BRepAdaptor_Curve C1( E1 ), C2( E2 );
+ Standard_Real tol = BRep_Tool::Tolerance( V );
+ Standard_Real angTol = 2e-3;
+ try {
+ OCC_CATCH_SIGNALS;
+ return BRepLProp::Continuity(C1, C2, u1, u2, tol, angTol);
+ }
+ catch (Standard_Failure) {
+ }
+ return GeomAbs_C0;
+}
+
+//================================================================================
+/*!
+ * \brief Return true if an edge can be considered straight
+ */
+//================================================================================
+
+bool SMESH_Algo::IsStraight( const TopoDS_Edge & E,
+ const bool degenResult)
+{
+ {
+ double f,l;
+ if ( BRep_Tool::Curve( E, f, l ).IsNull())
+ return degenResult;
+ }
+ BRepAdaptor_Curve curve( E );
+ switch( curve.GetType() )
+ {
+ case GeomAbs_Line:
+ return true;
+ case GeomAbs_Circle:
+ case GeomAbs_Ellipse:
+ case GeomAbs_Hyperbola:
+ case GeomAbs_Parabola:
+ return false;
+ // case GeomAbs_BezierCurve:
+ // case GeomAbs_BSplineCurve:
+ // case GeomAbs_OtherCurve:
+ default:;
+ }
+
+ // evaluate how far from a straight line connecting the curve ends
+ // stand internal points of the curve
+ double f = curve.FirstParameter();
+ double l = curve.LastParameter();
+ gp_Pnt pf = curve.Value( f );
+ gp_Pnt pl = curve.Value( l );
+ gp_Vec lineVec( pf, pl );
+ double lineLen2 = lineVec.SquareMagnitude();
+ if ( lineLen2 < std::numeric_limits< double >::min() )
+ return false; // E seems closed
+
+ double edgeTol = 10 * curve.Tolerance();
+ double lenTol2 = lineLen2 * 1e-4;
+ double tol2 = Min( edgeTol * edgeTol, lenTol2 );
+
+ const double nbSamples = 7;
+ for ( int i = 0; i < nbSamples; ++i )
+ {
+ double r = ( i + 1 ) / nbSamples;
+ gp_Pnt pi = curve.Value( f * r + l * ( 1 - r ));
+ gp_Vec vi( pf, pi );
+ double h2 = lineVec.Crossed( vi ).SquareMagnitude() / lineLen2;
+ if ( h2 > tol2 )
+ return false;
+ }
+ return true;
+}
+
+//================================================================================
+/*!
+ * \brief Return true if an edge has no 3D curve
+ */
+//================================================================================
+
+bool SMESH_Algo::isDegenerated( const TopoDS_Edge & E, const bool checkLength )
+{
+ if ( checkLength )
+ return EdgeLength( E ) == 0;
+ double f,l;
+ TopLoc_Location loc;
+ Handle(Geom_Curve) C = BRep_Tool::Curve( E, loc, f,l );
+ return C.IsNull();
+}
+
+//================================================================================
+/*!
+ * \brief Return the node built on a vertex
+ * \param V - the vertex
+ * \param meshDS - mesh
+ * \retval const SMDS_MeshNode* - found node or NULL
+ * \sa SMESH_MesherHelper::GetSubShapeByNode( const SMDS_MeshNode*, SMESHDS_Mesh* )
+ */
+//================================================================================
+
+const SMDS_MeshNode* SMESH_Algo::VertexNode(const TopoDS_Vertex& V,
+ const SMESHDS_Mesh* meshDS)
+{
+ if ( SMESHDS_SubMesh* sm = meshDS->MeshElements(V) ) {
+ SMDS_NodeIteratorPtr nIt= sm->GetNodes();
+ if (nIt->more())
+ return nIt->next();
+ }
+ return 0;
+}
+
+//=======================================================================
+/*!
+ * \brief Return the node built on a vertex.
+ * A node moved to other geometry by MergeNodes() is also returned.
+ * \param V - the vertex
+ * \param mesh - mesh
+ * \retval const SMDS_MeshNode* - found node or NULL
+ */
+//=======================================================================
+
+const SMDS_MeshNode* SMESH_Algo::VertexNode(const TopoDS_Vertex& V,
+ const SMESH_Mesh* mesh)
+{
+ const SMDS_MeshNode* node = VertexNode( V, mesh->GetMeshDS() );
+
+ if ( !node && mesh->HasModificationsToDiscard() )
+ {
+ PShapeIteratorPtr edgeIt = SMESH_MesherHelper::GetAncestors( V, *mesh, TopAbs_EDGE );
+ while ( const TopoDS_Shape* edge = edgeIt->next() )
+ if ( SMESHDS_SubMesh* edgeSM = mesh->GetMeshDS()->MeshElements( *edge ))
+ if ( edgeSM->NbElements() > 0 )
+ return VertexNode( V, edgeSM, mesh, /*checkV=*/false );
+ }
+ return node;
+}
+
+//=======================================================================
+/*!
+ * \brief Return the node built on a vertex.
+ * A node moved to other geometry by MergeNodes() is also returned.
+ * \param V - the vertex
+ * \param edgeSM - sub-mesh of a meshed EDGE sharing the vertex
+ * \param checkV - if \c true, presence of a node on the vertex is checked
+ * \retval const SMDS_MeshNode* - found node or NULL
+ */
+//=======================================================================
+
+const SMDS_MeshNode* SMESH_Algo::VertexNode(const TopoDS_Vertex& V,
+ const SMESHDS_SubMesh* edgeSM,
+ const SMESH_Mesh* mesh,
+ const bool checkV)
+{
+ const SMDS_MeshNode* node = checkV ? VertexNode( V, edgeSM->GetParent() ) : 0;
+
+ if ( !node && edgeSM )
+ {
+ // find nodes not shared by mesh segments
+ typedef set< const SMDS_MeshNode* > TNodeSet;
+ typedef map< const SMDS_MeshNode*, const SMDS_MeshNode* > TNodeMap;
+ TNodeMap notSharedNodes;
+ TNodeSet otherShapeNodes;
+ vector< const SMDS_MeshNode* > segNodes(3);
+ SMDS_ElemIteratorPtr segIt = edgeSM->GetElements();
+ while ( segIt->more() )
+ {
+ const SMDS_MeshElement* seg = segIt->next();
+ if ( seg->GetType() != SMDSAbs_Edge )
+ return node;
+ segNodes.assign( seg->begin_nodes(), seg->end_nodes() );
+ for ( int i = 0; i < 2; ++i )
+ {
+ const SMDS_MeshNode* n1 = segNodes[i];
+ const SMDS_MeshNode* n2 = segNodes[1-i];
+ pair<TNodeMap::iterator, bool> it2new = notSharedNodes.insert( make_pair( n1, n2 ));
+ if ( !it2new.second ) // n encounters twice
+ notSharedNodes.erase( it2new.first );
+ if ( n1->getshapeId() != edgeSM->GetID() )
+ otherShapeNodes.insert( n1 );
+ }
+ }
+ if ( otherShapeNodes.size() == 1 && notSharedNodes.empty() ) // a closed EDGE
+ return *otherShapeNodes.begin();
+
+ if ( notSharedNodes.size() == 2 ) // two end nodes found
+ {
+ SMESHDS_Mesh* meshDS = edgeSM->GetParent();
+ const TopoDS_Shape& E = meshDS->IndexToShape( edgeSM->GetID() );
+ if ( E.IsNull() || E.ShapeType() != TopAbs_EDGE )
+ return node;
+ const SMDS_MeshNode* n1 = notSharedNodes.begin ()->first;
+ const SMDS_MeshNode* n2 = notSharedNodes.rbegin()->first;
+ TopoDS_Shape S1 = SMESH_MesherHelper::GetSubShapeByNode( n1, meshDS );
+ if ( S1.ShapeType() == TopAbs_VERTEX && SMESH_MesherHelper::IsSubShape( S1, E ))
+ return n2;
+ TopoDS_Shape S2 = SMESH_MesherHelper::GetSubShapeByNode( n2, meshDS );
+ if ( S2.ShapeType() == TopAbs_VERTEX && SMESH_MesherHelper::IsSubShape( S2, E ))
+ return n1;
+ if ( edgeSM->NbElements() <= 2 || !mesh ) // one-two segments
+ {
+ gp_Pnt pV = BRep_Tool::Pnt( V );
+ double dist1 = pV.SquareDistance( SMESH_TNodeXYZ( n1 ));
+ double dist2 = pV.SquareDistance( SMESH_TNodeXYZ( n2 ));
+ return dist1 < dist2 ? n1 : n2;
+ }
+ if ( mesh )
+ {
+ SMESH_MesherHelper helper( const_cast<SMESH_Mesh&>( *mesh ));
+ const SMDS_MeshNode* n1i = notSharedNodes.begin ()->second;
+ const SMDS_MeshNode* n2i = notSharedNodes.rbegin()->second;
+ const TopoDS_Edge& edge = TopoDS::Edge( E );
+ bool posOK = true;
+ double pos1 = helper.GetNodeU( edge, n1i, n2i, &posOK );
+ double pos2 = helper.GetNodeU( edge, n2i, n1i, &posOK );
+ double posV = BRep_Tool::Parameter( V, edge );
+ if ( Abs( pos1 - posV ) < Abs( pos2 - posV )) return n1;
+ else return n2;
+ }
+ }
+ }
+ return node;
+}
+
+//=======================================================================
+//function : GetMeshError
+//purpose : Finds topological errors of a sub-mesh
+//WARNING : 1D check is NOT implemented so far
+//=======================================================================