X-Git-Url: http://git.salome-platform.org/gitweb/?p=modules%2Fsmesh.git;a=blobdiff_plain;f=src%2FStdMeshers%2FStdMeshers_ProjectionUtils.cxx;h=ae6f38419e465580eafdaad0461a7a1eaa107224;hp=3b69a201f4612ce648f92389c883be8da7489828;hb=b1f58b701eb4ec6fb4a14b070041f2c89e44723c;hpb=79b1ac2b6df9117f16f11d444b1f165d477a1813 diff --git a/src/StdMeshers/StdMeshers_ProjectionUtils.cxx b/src/StdMeshers/StdMeshers_ProjectionUtils.cxx index 3b69a201f..ae6f38419 100644 --- a/src/StdMeshers/StdMeshers_ProjectionUtils.cxx +++ b/src/StdMeshers/StdMeshers_ProjectionUtils.cxx @@ -1,51 +1,51 @@ -// SMESH SMESH : idl implementation based on 'SMESH' unit's calsses +// Copyright (C) 2007-2014 CEA/DEN, EDF R&D, OPEN CASCADE // -// Copyright (C) 2003 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. // +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. // +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + +// SMESH SMESH : idl implementation based on 'SMESH' unit's calsses // File : StdMeshers_ProjectionUtils.cxx // Created : Fri Oct 27 10:24:28 2006 // Author : Edward AGAPOV (eap) - -using namespace std; - +// #include "StdMeshers_ProjectionUtils.hxx" #include "StdMeshers_ProjectionSource1D.hxx" #include "StdMeshers_ProjectionSource2D.hxx" #include "StdMeshers_ProjectionSource3D.hxx" +#include "SMDS_EdgePosition.hxx" #include "SMESH_Algo.hxx" #include "SMESH_Block.hxx" #include "SMESH_Gen.hxx" +#include "SMESH_HypoFilter.hxx" #include "SMESH_Hypothesis.hxx" -#include "SMESH_IndexedDataMapOfShapeIndexedMapOfShape.hxx" #include "SMESH_Mesh.hxx" -#include "SMESH_MeshEditor.hxx" +#include "SMESH_MesherHelper.hxx" #include "SMESH_subMesh.hxx" #include "SMESH_subMeshEventListener.hxx" -#include "SMDS_EdgePosition.hxx" +#include "SMESH_MeshAlgos.hxx" #include "utilities.h" +#include #include #include #include @@ -55,6 +55,9 @@ using namespace std; #include #include #include +#include +#include +#include #include #include #include @@ -63,18 +66,23 @@ using namespace std; #include #include #include -#include -#include + +#include +#include + +using namespace std; #define RETURN_BAD_RESULT(msg) { MESSAGE(")-: Error: " << msg); return false; } -#define SHOW_VERTEX(v,msg) // { \ -// if ( v.IsNull() ) cout << msg << " NULL SHAPE" << endl; \ -// else if (v.ShapeType() == TopAbs_VERTEX) {\ -// gp_Pnt p = BRep_Tool::Pnt( TopoDS::Vertex( v ));\ -// cout << msg << (v).TShape().operator->()<<" ( " <()<ShapeToIndex(S), theMeshDS[1]->ShapeToIndex(S) ); + return long(S.TShape().operator->()); + } + + //================================================================================ + /*! + * \brief Write shape for debug purposes + */ + //================================================================================ + + bool _StoreBadShape(const TopoDS_Shape& shape) + { +#ifdef _DEBUG_ + const char* type[] ={"COMPOUND","COMPSOLID","SOLID","SHELL","FACE","WIRE","EDGE","VERTEX"}; + BRepTools::Write( shape, SMESH_Comment("/tmp/") << type[shape.ShapeType()] << "_" + << shape.TShape().operator->() << ".brep"); +#endif + return false; + } + //================================================================================ /*! * \brief Reverse order of edges in a list and their orientation @@ -95,31 +130,24 @@ namespace { */ //================================================================================ - void Reverse( list< TopoDS_Edge > & edges, const int nbEdges ) + void Reverse( list< TopoDS_Edge > & edges, const int nbEdges, const int firstEdge=0) { SHOW_LIST("BEFORE REVERSE", edges); list< TopoDS_Edge >::iterator eIt = edges.begin(); - if ( edges.size() == nbEdges ) - { - edges.reverse(); - } - else // reverse only the given nb of edges + std::advance( eIt, firstEdge ); + list< TopoDS_Edge >::iterator eBackIt = eIt; + for ( int i = 0; i < nbEdges; ++i, ++eBackIt ) + eBackIt->Reverse(); // reverse edge + // reverse list + --eBackIt; + while ( eIt != eBackIt ) { - // look for the last edge to be reversed - list< TopoDS_Edge >::iterator eBackIt = edges.begin(); - for ( int i = 1; i < nbEdges; ++i ) - ++eBackIt; - // reverse - while ( eIt != eBackIt ) { - std::swap( *eIt, *eBackIt ); - SHOW_LIST("# AFTER SWAP", edges) + std::swap( *eIt, *eBackIt ); + SHOW_LIST("# AFTER SWAP", edges) if ( (++eIt) != eBackIt ) --eBackIt; - } } - for ( eIt = edges.begin(); eIt != edges.end(); ++eIt ) - eIt->Reverse(); SHOW_LIST("ATFER REVERSE", edges) } @@ -163,8 +191,7 @@ namespace { if ( nbEdges == 2 && IsPropagationPossible( theMesh1, theMesh2 ) ) { list< TopoDS_Edge >::iterator eIt2 = ++edges2.begin(); // 2nd edge of the 2nd face - TopoDS_Edge edge2 = - StdMeshers_ProjectionUtils::GetPropagationEdge( theMesh1, *eIt2, edges1.front() ).second; + TopoDS_Edge edge2 = HERE::GetPropagationEdge( theMesh1, *eIt2, edges1.front() ).second; if ( !edge2.IsNull() ) { // propagation found for the second edge Reverse( edges2, nbEdges ); return true; @@ -190,31 +217,217 @@ namespace { list subMeshes = tgtMesh1->GetGroupSubMeshesContaining(tgtShape); list::iterator sm = subMeshes.begin(); int type, last = TopAbs_SHAPE; - StdMeshers_ProjectionUtils util; for ( ; sm != subMeshes.end(); ++sm ) { const TopoDS_Shape & group = (*sm)->GetSubShape(); // check if group is similar to srcGroup for ( type = srcGroup.ShapeType(); type < last; ++type) - if ( util.Count( srcGroup, (TopAbs_ShapeEnum)type, 0) != - util.Count( group, (TopAbs_ShapeEnum)type, 0)) + if ( SMESH_MesherHelper::Count( srcGroup, (TopAbs_ShapeEnum)type, 0) != + SMESH_MesherHelper::Count( group, (TopAbs_ShapeEnum)type, 0)) break; if ( type == last ) return group; } return TopoDS_Shape(); } -} + + //================================================================================ + /*! + * \brief Find association of groups at top and bottom of prism + */ + //================================================================================ + + bool AssocGroupsByPropagation(const TopoDS_Shape& theGroup1, + const TopoDS_Shape& theGroup2, + SMESH_Mesh& theMesh, + HERE::TShapeShapeMap& theMap) + { + // If groups are on top and bottom of prism then we can associate + // them using "vertical" (or "side") edges and faces of prism since + // they connect corresponding vertices and edges of groups. + + TopTools_IndexedMapOfShape subshapes1, subshapes2; + TopExp::MapShapes( theGroup1, subshapes1 ); + TopExp::MapShapes( theGroup2, subshapes2 ); + TopTools_ListIteratorOfListOfShape ancestIt; + + // Iterate on vertices of group1 to find corresponding vertices in group2 + // and associate adjacent edges and faces + + TopTools_MapOfShape verticShapes; + TopExp_Explorer vExp1( theGroup1, TopAbs_VERTEX ); + for ( ; vExp1.More(); vExp1.Next() ) + { + const TopoDS_Vertex& v1 = TopoDS::Vertex( vExp1.Current() ); + if ( theMap.IsBound( v1 )) continue; // already processed + + // Find "vertical" edge ending in v1 and whose other vertex belongs to group2 + TopoDS_Shape verticEdge, v2; + ancestIt.Initialize( theMesh.GetAncestors( v1 )); + for ( ; verticEdge.IsNull() && ancestIt.More(); ancestIt.Next() ) + { + if ( ancestIt.Value().ShapeType() != TopAbs_EDGE ) continue; + v2 = HERE::GetNextVertex( TopoDS::Edge( ancestIt.Value() ), v1 ); + if ( subshapes2.Contains( v2 )) + verticEdge = ancestIt.Value(); + } + if ( verticEdge.IsNull() ) + return false; + + HERE::InsertAssociation( v1, v2, theMap); + + // Associate edges by vertical faces sharing the found vertical edge + ancestIt.Initialize( theMesh.GetAncestors( verticEdge ) ); + for ( ; ancestIt.More(); ancestIt.Next() ) + { + if ( ancestIt.Value().ShapeType() != TopAbs_FACE ) continue; + if ( !verticShapes.Add( ancestIt.Value() )) continue; + const TopoDS_Face& face = TopoDS::Face( ancestIt.Value() ); + + // get edges of the face + TopoDS_Edge edgeGr1, edgeGr2, verticEdge2; + list< TopoDS_Edge > edges; list< int > nbEdgesInWire; + SMESH_Block::GetOrderedEdges( face, edges, nbEdgesInWire, v1); + if ( nbEdgesInWire.front() != 4 ) + return _StoreBadShape( face ); + list< TopoDS_Edge >::iterator edge = edges.begin(); + if ( verticEdge.IsSame( *edge )) { + edgeGr2 = *(++edge); + verticEdge2 = *(++edge); + edgeGr1 = *(++edge); + } else { + edgeGr1 = *(edge++); + verticEdge2 = *(edge++); + edgeGr2 = *(edge++); + } + + HERE::InsertAssociation( edgeGr1, edgeGr2.Reversed(), theMap); + } + } + + // Associate faces + TopoDS_Iterator gr1It( theGroup1 ); + if ( gr1It.Value().ShapeType() == TopAbs_FACE ) + { + // find a boundary edge of group1 to start from + TopoDS_Shape bndEdge = HERE::GetBoundaryEdge( theGroup1, theMesh ); + if ( bndEdge.IsNull() ) + return false; + + list< TopoDS_Shape > edges(1, bndEdge); + list< TopoDS_Shape >::iterator edge1 = edges.begin(); + for ( ; edge1 != edges.end(); ++edge1 ) + { + // there must be one or zero not associated faces between ancestors of edge + // belonging to theGroup1 + TopoDS_Shape face1; + ancestIt.Initialize( theMesh.GetAncestors( *edge1 ) ); + for ( ; ancestIt.More() && face1.IsNull(); ancestIt.Next() ) { + if ( ancestIt.Value().ShapeType() == TopAbs_FACE && + !theMap.IsBound( ancestIt.Value() ) && + subshapes1.Contains( ancestIt.Value() )) + face1 = ancestIt.Value(); + + // add edges of face1 to start searching for adjacent faces from + for ( TopExp_Explorer e(face1, TopAbs_EDGE); e.More(); e.Next()) + if ( !edge1->IsSame( e.Current() )) + edges.push_back( e.Current() ); + } + if ( !face1.IsNull() ) { + // find the corresponding face of theGroup2 + TopoDS_Shape edge2 = theMap( *edge1 ); + TopoDS_Shape face2; + ancestIt.Initialize( theMesh.GetAncestors( edge2 ) ); + for ( ; ancestIt.More() && face2.IsNull(); ancestIt.Next() ) { + if ( ancestIt.Value().ShapeType() == TopAbs_FACE && + !theMap.IsBound( ancestIt.Value(), /*is2nd=*/true ) && + subshapes2.Contains( ancestIt.Value() )) + face2 = ancestIt.Value(); + } + if ( face2.IsNull() ) + return false; + + HERE::InsertAssociation( face1, face2, theMap); + } + } + } + return true; + } + + //================================================================================ + /*! + * \brief Return true if uv position of the vIndex-th vertex of edge on face is close + * enough to given uv + */ + //================================================================================ + + bool sameVertexUV( const TopoDS_Edge& edge, + const TopoDS_Face& face, + const int& vIndex, + const gp_Pnt2d& uv, + const double& tol2d ) + { + TopoDS_Vertex VV[2]; + TopExp::Vertices( edge, VV[0], VV[1], true); + gp_Pnt2d v1UV = BRep_Tool::Parameters( VV[vIndex], face); + double dist2d = v1UV.Distance( uv ); + return dist2d < tol2d; + } + + //================================================================================ + /*! + * \brief Returns an EDGE suitable for search of initial vertex association + */ + //================================================================================ + + bool getOuterEdges( const TopoDS_Shape shape, + SMESH_Mesh& mesh, + std::list< TopoDS_Edge >& allBndEdges ) + { + if ( shape.ShapeType() == TopAbs_COMPOUND ) + { + TopoDS_Iterator it( shape ); + if ( it.More() && it.Value().ShapeType() == TopAbs_FACE ) // group of FACEs + { + // look for a boundary EDGE of a group + StdMeshers_ProjectionUtils::GetBoundaryEdge( shape, mesh, &allBndEdges ); + if ( !allBndEdges.empty() ) + return true; + } + } + TopExp_Explorer expF( shape, TopAbs_FACE ), expE; + if ( expF.More() ) { + for ( ; expF.More(); expF.Next() ) { + TopoDS_Shape wire = + StdMeshers_ProjectionUtils::OuterShape( TopoDS::Face( expF.Current() ), TopAbs_WIRE ); + for ( expE.Init( wire, TopAbs_EDGE ); expE.More(); expE.Next() ) + if ( !SMESH_MesherHelper::IsClosedEdge( TopoDS::Edge( expE.Current() ))) + allBndEdges.push_back( TopoDS::Edge( expE.Current() )); + } + } + else if ( shape.ShapeType() != TopAbs_EDGE) { // no faces + for ( expE.Init( shape, TopAbs_EDGE ); expE.More(); expE.Next() ) + if ( !SMESH_MesherHelper::IsClosedEdge( TopoDS::Edge( expE.Current() ))) + allBndEdges.push_back( TopoDS::Edge( expE.Current() )); + } + else if ( shape.ShapeType() == TopAbs_EDGE ) { + if ( !SMESH_MesherHelper::IsClosedEdge( TopoDS::Edge( shape ))) + allBndEdges.push_back( TopoDS::Edge( shape )); + } + return !allBndEdges.empty(); + } + +} // namespace //======================================================================= -/*! - * \brief Looks for association of all subshapes of two shapes - * \param theShape1 - shape 1 - * \param theMesh1 - mesh built on shape 1 - * \param theShape2 - shape 2 - * \param theMesh2 - mesh built on shape 2 - * \param theAssociation - association map to be filled that may - * contain association of one or two pairs of vertices - * \retval bool - true if association found +/* + * Looks for association of all sub-shapes of two shapes + * \param theShape1 - target shape + * \param theMesh1 - mesh built on shape 1 + * \param theShape2 - source shape + * \param theMesh2 - mesh built on shape 2 + * \param theAssociation - association map to be filled that may + * contain association of one or two pairs of vertices + * \retval bool - true if association found */ //======================================================================= @@ -224,8 +437,31 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the SMESH_Mesh* theMesh2, TShapeShapeMap & theMap) { + // Structure of this long function is following + // 1) Group -> Group projection: theShape1 is a group member, + // theShape2 is another group. We find a group theShape1 is in and recall self. + // 2) Accosiate same shapes with different location (partners). + // 3) If vertex association is given, perform accosiation according to shape type: + // switch ( ShapeType ) { + // case TopAbs_EDGE: + // case ...: + // } + // 4) else try to accosiate in different ways: + // a) accosiate shapes by propagation and other simple cases + // switch ( ShapeType ) { + // case TopAbs_EDGE: + // case ...: + // } + // b) find association of a couple of vertices and recall self. + // + + theMeshDS[0] = theMesh1->GetMeshDS(); // debug + theMeshDS[1] = theMesh2->GetMeshDS(); + + // ================================================================================= + // 1) Is it the case of associating a group member -> another group? (PAL16202, 16203) + // ================================================================================= if ( theShape1.ShapeType() != theShape2.ShapeType() ) { - // is it the case of a group member -> another group? (PAL16202, 16203) TopoDS_Shape group1, group2; if ( theShape1.ShapeType() == TopAbs_COMPOUND ) { group1 = theShape1; @@ -241,11 +477,34 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the return FindSubShapeAssociation(group1, theMesh1, group2, theMesh2, theMap ); } - bool bidirect = ( !theShape1.IsSame( theShape2 )); + // ============ + // 2) Is partner? + // ============ + bool partner = theShape1.IsPartner( theShape2 ); + TopTools_DataMapIteratorOfDataMapOfShapeShape vvIt( theMap._map1to2 ); + for ( ; partner && vvIt.More(); vvIt.Next() ) + partner = vvIt.Key().IsPartner( vvIt.Value() ); + + if ( partner ) // Same shape with different location + { + // recursively associate all sub-shapes of theShape1 and theShape2 + typedef list< pair< TopoDS_Shape, TopoDS_Shape > > TShapePairsList; + TShapePairsList shapesQueue( 1, make_pair( theShape1, theShape2 )); + TShapePairsList::iterator s1_s2 = shapesQueue.begin(); + for ( ; s1_s2 != shapesQueue.end(); ++s1_s2 ) + { + InsertAssociation( s1_s2->first, s1_s2->second, theMap ); + TopoDS_Iterator s1It( s1_s2->first), s2It( s1_s2->second ); + for ( ; s1It.More(); s1It.Next(), s2It.Next() ) + shapesQueue.push_back( make_pair( s1It.Value(), s2It.Value() )); + } + return true; + } + if ( !theMap.IsEmpty() ) { //====================================================================== - // HAS initial vertex association + // 3) HAS initial vertex association //====================================================================== switch ( theShape1.ShapeType() ) { // ---------------------------------------------------------------------- @@ -255,14 +514,16 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the RETURN_BAD_RESULT("Wrong map extent " << theMap.Extent() ); TopoDS_Edge edge1 = TopoDS::Edge( theShape1 ); TopoDS_Edge edge2 = TopoDS::Edge( theShape2 ); + if ( edge1.Orientation() >= TopAbs_INTERNAL ) edge1.Orientation( TopAbs_FORWARD ); + if ( edge2.Orientation() >= TopAbs_INTERNAL ) edge2.Orientation( TopAbs_FORWARD ); TopoDS_Vertex VV1[2], VV2[2]; TopExp::Vertices( edge1, VV1[0], VV1[1] ); TopExp::Vertices( edge2, VV2[0], VV2[1] ); int i1 = 0, i2 = 0; if ( theMap.IsBound( VV1[ i1 ] )) i1 = 1; if ( theMap.IsBound( VV2[ i2 ] )) i2 = 1; - InsertAssociation( VV1[ i1 ], VV2[ i2 ], theMap, bidirect); - InsertAssociation( theShape1, theShape2, theMap, bidirect ); + InsertAssociation( VV1[ i1 ], VV2[ i2 ], theMap ); + InsertAssociation( theShape1, theShape2, theMap ); return true; } // ---------------------------------------------------------------------- @@ -270,6 +531,8 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the // ---------------------------------------------------------------------- TopoDS_Face face1 = TopoDS::Face( theShape1 ); TopoDS_Face face2 = TopoDS::Face( theShape2 ); + if ( face1.Orientation() >= TopAbs_INTERNAL ) face1.Orientation( TopAbs_FORWARD ); + if ( face2.Orientation() >= TopAbs_INTERNAL ) face2.Orientation( TopAbs_FORWARD ); TopoDS_Vertex VV1[2], VV2[2]; // find a not closed edge of face1 both vertices of which are associated @@ -299,12 +562,12 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the list< TopoDS_Edge >::iterator eIt2 = edges2.begin(); for ( ; eIt1 != edges1.end(); ++eIt1, ++eIt2 ) { - InsertAssociation( *eIt1, *eIt2, theMap, bidirect); + InsertAssociation( *eIt1, *eIt2, theMap ); VV1[0] = TopExp::FirstVertex( *eIt1, true ); VV2[0] = TopExp::FirstVertex( *eIt2, true ); - InsertAssociation( VV1[0], VV2[0], theMap, bidirect); + InsertAssociation( VV1[0], VV2[0], theMap ); } - InsertAssociation( theShape1, theShape2, theMap, bidirect ); + InsertAssociation( theShape1, theShape2, theMap ); return true; } // ---------------------------------------------------------------------- @@ -312,11 +575,12 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the case TopAbs_SOLID: { // ---------------------------------------------------------------------- TopoDS_Vertex VV1[2], VV2[2]; - // find a not closed edge of shape1 both vertices of which are associated + // try to find a not closed edge of shape1 both vertices of which are associated TopoDS_Edge edge1; TopExp_Explorer exp ( theShape1, TopAbs_EDGE ); for ( ; VV2[ 1 ].IsNull() && exp.More(); exp.Next() ) { edge1 = TopoDS::Edge( exp.Current() ); + if ( edge1.Orientation() >= TopAbs_INTERNAL ) edge1.Orientation( TopAbs_FORWARD ); TopExp::Vertices( edge1 , VV1[0], VV1[1] ); if ( theMap.IsBound( VV1[0] )) { VV2[ 0 ] = TopoDS::Vertex( theMap( VV1[0] )); @@ -326,11 +590,12 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the } if ( VV2[ 1 ].IsNull() ) // 2 bound vertices not found RETURN_BAD_RESULT("2 bound vertices not found" ); + // get an edge2 of theShape2 corresponding to edge1 TopoDS_Edge edge2 = GetEdgeByVertices( theMesh2, VV2[ 0 ], VV2[ 1 ]); if ( edge2.IsNull() ) RETURN_BAD_RESULT("GetEdgeByVertices() failed"); - // build map of edge to faces if shapes are not subshapes of main ones + // build map of edge to faces if shapes are not sub-shapes of main ones bool isSubOfMain = false; if ( SMESHDS_SubMesh * sm = theMesh1->GetMeshDS()->MeshElements( theShape1 )) isSubOfMain = !sm->IsComplexSubmesh(); @@ -357,7 +622,8 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the TopTools_ListIteratorOfListOfShape ancestIt1( edgeToFace1.FindFromKey( edge1 )); for ( ; F1.IsNull() && ancestIt1.More(); ancestIt1.Next() ) if ( ancestIt1.Value().ShapeType() == TopAbs_FACE ) - F1 = ancestIt1.Value().Oriented( TopAbs_FORWARD ); + F1 = ancestIt1.Value().Oriented //( TopAbs_FORWARD ); + ( SMESH_MesherHelper::GetSubShapeOri( theShape1, ancestIt1.Value() )); if ( F1.IsNull() ) RETURN_BAD_RESULT(" Face1 not found"); @@ -365,7 +631,8 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the TopTools_ListIteratorOfListOfShape ancestIt2( edgeToFace2.FindFromKey( edge2 )); for ( int i = 0; FF2[1].IsNull() && ancestIt2.More(); ancestIt2.Next() ) if ( ancestIt2.Value().ShapeType() == TopAbs_FACE ) - FF2[ i++ ] = ancestIt2.Value().Oriented( TopAbs_FORWARD ); + FF2[ i++ ] = ancestIt2.Value().Oriented // ( TopAbs_FORWARD ); + ( SMESH_MesherHelper::GetSubShapeOri( theShape2, ancestIt2.Value() )); // get oriented edge1 and edge2 from F1 and FF2[0] for ( exp.Init( F1, TopAbs_EDGE ); exp.More(); exp.Next() ) @@ -383,7 +650,7 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the TopExp::Vertices( edge1, VV1[0], VV1[1], true ); TopExp::Vertices( edge2, VV2[0], VV2[1], true ); F2 = FF2[ 0 ]; // (F2 !) - if ( !VV1[ 0 ].IsSame( theMap( VV2[ 0 ]))) { + if ( !VV1[ 0 ].IsSame( theMap( VV2[ 0 ], /*is2=*/true))) { edge2.Reverse(); if ( FF2[ 1 ].IsNull() ) F2.Reverse(); @@ -393,7 +660,7 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the TopTools_MapOfShape boundEdges; - // association of face subshapes and neighbour faces + // association of face sub-shapes and neighbour faces list< pair < TopoDS_Face, TopoDS_Edge > > FE1, FE2; list< pair < TopoDS_Face, TopoDS_Edge > >::iterator fe1, fe2; FE1.push_back( make_pair( TopoDS::Face( F1 ), edge1 )); @@ -410,7 +677,7 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the list< TopoDS_Edge > edges1, edges2; int nbE = FindFaceAssociation( face1, VV1, face2, VV2, edges1, edges2 ); if ( !nbE ) RETURN_BAD_RESULT("FindFaceAssociation() failed"); - InsertAssociation( face1, face2, theMap, bidirect); // assoc faces + InsertAssociation( face1, face2, theMap ); // assoc faces MESSAGE("Assoc FACE " << theMesh1->GetMeshDS()->ShapeToIndex( face1 )<< " to " << theMesh2->GetMeshDS()->ShapeToIndex( face2 )); if ( nbE == 2 && (edge1.IsSame( edges1.front())) != (edge2.IsSame( edges2.front()))) @@ -422,12 +689,12 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the for ( ; eIt1 != edges1.end(); ++eIt1, ++eIt2 ) { if ( !boundEdges.Add( *eIt1 )) continue; // already associated - InsertAssociation( *eIt1, *eIt2, theMap, bidirect); // assoc edges + InsertAssociation( *eIt1, *eIt2, theMap ); // assoc edges MESSAGE("Assoc edge " << theMesh1->GetMeshDS()->ShapeToIndex( *eIt1 )<< " to " << theMesh2->GetMeshDS()->ShapeToIndex( *eIt2 )); VV1[0] = TopExp::FirstVertex( *eIt1, true ); VV2[0] = TopExp::FirstVertex( *eIt2, true ); - InsertAssociation( VV1[0], VV2[0], theMap, bidirect); // assoc vertices + InsertAssociation( VV1[0], VV2[0], theMap ); // assoc vertices MESSAGE("Assoc vertex " << theMesh1->GetMeshDS()->ShapeToIndex( VV1[0] )<< " to " << theMesh2->GetMeshDS()->ShapeToIndex( VV2[0] )); @@ -440,7 +707,7 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the } } } - InsertAssociation( theShape1, theShape2, theMap, bidirect ); + InsertAssociation( theShape1, theShape2, theMap ); return true; } // ---------------------------------------------------------------------- @@ -449,7 +716,7 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the // Maybe groups contain only one member TopoDS_Iterator it1( theShape1 ), it2( theShape2 ); TopAbs_ShapeEnum memberType = it1.Value().ShapeType(); - int nbMembers = Count( theShape1, memberType, true ); + int nbMembers = SMESH_MesherHelper::Count( theShape1, memberType, true ); if ( nbMembers == 0 ) return true; if ( nbMembers == 1 ) { return FindSubShapeAssociation( it1.Value(), theMesh1, it2.Value(), theMesh2, theMap ); @@ -479,7 +746,7 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the if ( !initAssocOK ) { // for shell association there must be an edge with both vertices bound TopoDS_Vertex v1, v2; - TopExp::Vertices( TopoDS::Edge( it1.Value()), v1, v2 ); + TopExp::Vertices( TopoDS::Edge( it1.Value().Oriented(TopAbs_FORWARD)), v1, v2 ); initAssocOK = ( theMap.IsBound( v1 ) && theMap.IsBound( v2 )); } } @@ -498,7 +765,8 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the if ( groupEdges[ is2ndGroup ].Contains( f.Current() )) if ( ++nbGroupEdges > 1 ) break; - bool add = (nbGroupEdges > 1 || Count( face, TopAbs_EDGE, true ) == 1 ); + bool add = (nbGroupEdges > 1 || + SMESH_MesherHelper::Count( face, TopAbs_EDGE, true ) == 1 ); if ( !add ) { add = true; for ( TopExp_Explorer v( face, TopAbs_VERTEX ); add && v.More(); v.Next()) @@ -515,8 +783,8 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the } // Associate shells // - int nbFaces1 = Count( shell1, TopAbs_FACE, 0 ); - int nbFaces2 = Count( shell2, TopAbs_FACE, 0 ); + int nbFaces1 = SMESH_MesherHelper:: Count( shell1, TopAbs_FACE, 0 ); + int nbFaces2 = SMESH_MesherHelper:: Count( shell2, TopAbs_FACE, 0 ); if ( nbFaces1 != nbFaces2 ) RETURN_BAD_RESULT("Different nb of faces found for shells"); if ( nbFaces1 > 0 ) { @@ -562,7 +830,7 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the TShapeShapeMap tmpMap; ok = FindSubShapeAssociation( comp[0], theMesh1, comp[1], theMesh2, tmpMap ); if ( ok ) { - TopTools_DataMapIteratorOfDataMapOfShapeShape mapIt( tmpMap ); + TopTools_DataMapIteratorOfDataMapOfShapeShape mapIt( tmpMap._map1to2 ); for ( ; mapIt.More(); mapIt.Next() ) theMap.Bind( mapIt.Key(), mapIt.Value()); } @@ -621,13 +889,13 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the TopoDS_Edge e1 = TopoDS::Edge( edges1.First() ); v2e[0].UnBind( V[0] ); v2e[1].UnBind( V[1] ); - InsertAssociation( e0, e1, theMap, bidirect ); + InsertAssociation( e0, e1, theMap ); MESSAGE("Assoc edge " << theMesh1->GetMeshDS()->ShapeToIndex( e0 )<< " to " << theMesh2->GetMeshDS()->ShapeToIndex( e1 )); V[0] = GetNextVertex( e0, V[0] ); V[1] = GetNextVertex( e1, V[1] ); if ( !V[0].IsNull() ) { - InsertAssociation( V[0], V[1], theMap, bidirect ); + InsertAssociation( V[0], V[1], theMap ); MESSAGE("Assoc vertex " << theMesh1->GetMeshDS()->ShapeToIndex( V[0] )<< " to " << theMesh2->GetMeshDS()->ShapeToIndex( V[1] )); } @@ -653,9 +921,9 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the } else { v1n = v1e1; e1b = edges1.First(); e1n = edges1.Last(); } - InsertAssociation( e0b, e1b, theMap, bidirect ); - InsertAssociation( e0n, e1n, theMap, bidirect ); - InsertAssociation( v0n, v1n, theMap, bidirect ); + InsertAssociation( e0b, e1b, theMap ); + InsertAssociation( e0n, e1n, theMap ); + InsertAssociation( v0n, v1n, theMap ); MESSAGE("Assoc edge " << theMesh1->GetMeshDS()->ShapeToIndex( e0b )<< " to " << theMesh2->GetMeshDS()->ShapeToIndex( e1b )); MESSAGE("Assoc edge " << theMesh1->GetMeshDS()->ShapeToIndex( e0n )<< @@ -682,7 +950,7 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the } // end case of available initial vertex association //====================================================================== - // NO INITIAL VERTEX ASSOCIATION + // 4) NO INITIAL VERTEX ASSOCIATION //====================================================================== switch ( theShape1.ShapeType() ) { @@ -699,24 +967,25 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the TopoDS_Vertex VV1[2], VV2[2]; TopExp::Vertices( edge1, VV1[0], VV1[1], true ); TopExp::Vertices( prpEdge, VV2[0], VV2[1], true ); - InsertAssociation( VV1[ 0 ], VV2[ 0 ], theMap, bidirect); - InsertAssociation( VV1[ 1 ], VV2[ 1 ], theMap, bidirect); + InsertAssociation( VV1[ 0 ], VV2[ 0 ], theMap ); + InsertAssociation( VV1[ 1 ], VV2[ 1 ], theMap ); if ( VV1[0].IsSame( VV1[1] ) || // one of edges is closed VV2[0].IsSame( VV2[1] ) ) { - InsertAssociation( edge1, prpEdge, theMap, bidirect); // insert with a proper orientation + InsertAssociation( edge1, prpEdge, theMap ); // insert with a proper orientation } - InsertAssociation( theShape1, theShape2, theMap, bidirect ); + InsertAssociation( theShape1, theShape2, theMap ); return true; // done } } - if ( IsClosedEdge( edge1 ) && IsClosedEdge( edge2 )) + if ( SMESH_MesherHelper::IsClosedEdge( edge1 ) && + SMESH_MesherHelper::IsClosedEdge( edge2 )) { // TODO: find out a proper orientation (is it possible?) - InsertAssociation( edge1, edge2, theMap, bidirect); // insert with a proper orientation + InsertAssociation( edge1, edge2, theMap ); // insert with a proper orientation InsertAssociation( TopExp::FirstVertex(edge1), TopExp::FirstVertex(edge2), - theMap, bidirect); - InsertAssociation( theShape1, theShape2, theMap, bidirect ); + theMap ); + InsertAssociation( theShape1, theShape2, theMap ); return true; // done } break; // try by vertex closeness @@ -728,80 +997,188 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the { TopoDS_Face face1 = TopoDS::Face(theShape1); TopoDS_Face face2 = TopoDS::Face(theShape2); + if ( face1.Orientation() >= TopAbs_INTERNAL ) face1.Orientation( TopAbs_FORWARD ); + if ( face2.Orientation() >= TopAbs_INTERNAL ) face2.Orientation( TopAbs_FORWARD ); TopoDS_Edge edge1, edge2; // get outer edge of theShape1 - edge1 = TopoDS::Edge( OuterShape( face1, TopAbs_EDGE )); - // find out if any edge of face2 is a propagation edge of outer edge1 - map propag_edges; // use map to find the closest propagation edge - for ( TopExp_Explorer exp( face2, TopAbs_EDGE ); exp.More(); exp.Next() ) { - edge2 = TopoDS::Edge( exp.Current() ); - pair step_edge = GetPropagationEdge( theMesh1, edge2, edge1 ); - if ( !step_edge.second.IsNull() ) { // propagation found - propag_edges.insert( step_edge ); + TopoDS_Shape wire = OuterShape( face1, TopAbs_WIRE ); + //edge1 = TopoDS::Edge( OuterShape( face1, TopAbs_EDGE )); + // use map to find the closest propagation edge + map > propag_edges; + for ( TopoDS_Iterator edgeIt( wire ); edgeIt.More(); edgeIt.Next() ) + { + edge1 = TopoDS::Edge( edgeIt.Value() ); + // find out if any edge of face2 is a propagation edge of outer edge1 + for ( TopExp_Explorer exp( face2, TopAbs_EDGE ); exp.More(); exp.Next() ) { + edge2 = TopoDS::Edge( exp.Current() ); + pair step_edge = GetPropagationEdge( theMesh1, edge2, edge1 ); + if ( !step_edge.second.IsNull() ) { // propagation found + propag_edges.insert( make_pair( step_edge.first, + ( make_pair( edge1, step_edge.second )))); + if ( step_edge.first == 1 ) break; // most close found + } } + if ( !propag_edges.empty() && propag_edges.begin()->first == 1 ) break; } if ( !propag_edges.empty() ) // propagation found { - edge2 = propag_edges.begin()->second; + edge1 = propag_edges.begin()->second.first; + edge2 = propag_edges.begin()->second.second; TopoDS_Vertex VV1[2], VV2[2]; TopExp::Vertices( edge1, VV1[0], VV1[1], true ); TopExp::Vertices( edge2, VV2[0], VV2[1], true ); list< TopoDS_Edge > edges1, edges2; int nbE = FindFaceAssociation( face1, VV1, face2, VV2, edges1, edges2 ); if ( !nbE ) RETURN_BAD_RESULT("FindFaceAssociation() failed"); - if ( nbE == 2 ) // only 2 edges + // take care of proper association of propagated edges + bool same1 = edge1.IsSame( edges1.front() ); + bool same2 = edge2.IsSame( edges2.front() ); + if ( same1 != same2 ) { - // take care of proper association of propagated edges - bool same1 = edge1.IsSame( edges1.front() ); - bool same2 = edge2.IsSame( edges2.front() ); - if ( same1 != same2 ) - Reverse(edges2, nbE); + Reverse(edges2, nbE); + if ( nbE != 2 ) // 2 degen edges of 4 (issue 0021144) + edges2.splice( edges2.end(), edges2, edges2.begin()); } // store association list< TopoDS_Edge >::iterator eIt1 = edges1.begin(); list< TopoDS_Edge >::iterator eIt2 = edges2.begin(); for ( ; eIt1 != edges1.end(); ++eIt1, ++eIt2 ) { - InsertAssociation( *eIt1, *eIt2, theMap, bidirect); + InsertAssociation( *eIt1, *eIt2, theMap ); VV1[0] = TopExp::FirstVertex( *eIt1, true ); VV2[0] = TopExp::FirstVertex( *eIt2, true ); - InsertAssociation( VV1[0], VV2[0], theMap, bidirect); + InsertAssociation( VV1[0], VV2[0], theMap ); } - InsertAssociation( theShape1, theShape2, theMap, bidirect ); + InsertAssociation( theShape1, theShape2, theMap ); return true; } } break; // try by vertex closeness } + case TopAbs_COMPOUND: { + // ---------------------------------------------------------------------- + if ( IsPropagationPossible( theMesh1, theMesh2 )) { + + // try to accosiate all using propagation + if ( AssocGroupsByPropagation( theShape1, theShape2, *theMesh1, theMap )) + return true; + + // find a boundary edge of theShape1 + TopoDS_Edge E = GetBoundaryEdge( theShape1, *theMesh1 ); + if ( E.IsNull() ) + break; // try by vertex closeness + + // find association for vertices of edge E + TopoDS_Vertex VV1[2], VV2[2]; + for(TopExp_Explorer eexp(E, TopAbs_VERTEX); eexp.More(); eexp.Next()) { + TopoDS_Vertex V1 = TopoDS::Vertex( eexp.Current() ); + // look for an edge ending in E whose one vertex is in theShape1 + // and the other, in theShape2 + const TopTools_ListOfShape& Ancestors = theMesh1->GetAncestors(V1); + TopTools_ListIteratorOfListOfShape ita(Ancestors); + for(; ita.More(); ita.Next()) { + if( ita.Value().ShapeType() != TopAbs_EDGE ) continue; + TopoDS_Edge edge = TopoDS::Edge(ita.Value()); + bool FromShape1 = false; + for(TopExp_Explorer expe(theShape1, TopAbs_EDGE); expe.More(); expe.Next() ) { + if(edge.IsSame(expe.Current())) { + FromShape1 = true; + break; + } + } + if(!FromShape1) { + // is it an edge between theShape1 and theShape2? + TopExp_Explorer expv(edge, TopAbs_VERTEX); + TopoDS_Vertex V2 = TopoDS::Vertex( expv.Current() ); + if(V2.IsSame(V1)) { + expv.Next(); + V2 = TopoDS::Vertex( expv.Current() ); + } + bool FromShape2 = false; + for ( expv.Init( theShape2, TopAbs_VERTEX ); expv.More(); expv.Next()) { + if ( V2.IsSame( expv.Current() )) { + FromShape2 = true; + break; + } + } + if ( FromShape2 ) { + if ( VV1[0].IsNull() ) + VV1[0] = V1, VV2[0] = V2; + else + VV1[1] = V1, VV2[1] = V2; + break; // from loop on ancestors of V1 + } + } + } + } + if ( !VV1[1].IsNull() ) { + InsertAssociation( VV1[0], VV2[0], theMap ); + InsertAssociation( VV1[1], VV2[1], theMap ); + return FindSubShapeAssociation( theShape1, theMesh1, theShape2, theMesh2, theMap); + } + } + break; // try by vertex closeness + } default:; } - // Find association by closeness of vertices - // ------------------------------------------ + // 4.b) Find association by closeness of vertices + // ---------------------------------------------- TopTools_IndexedMapOfShape vMap1, vMap2; TopExp::MapShapes( theShape1, TopAbs_VERTEX, vMap1 ); TopExp::MapShapes( theShape2, TopAbs_VERTEX, vMap2 ); + TopoDS_Vertex VV1[2], VV2[2]; if ( vMap1.Extent() != vMap2.Extent() ) - RETURN_BAD_RESULT("Different nb of vertices"); + { + if ( SMESH_MesherHelper:: Count( theShape1, TopAbs_EDGE, /*ignoreSame=*/false ) != + SMESH_MesherHelper:: Count( theShape2, TopAbs_EDGE, /*ignoreSame=*/false )) + RETURN_BAD_RESULT("Different nb of vertices"); + } if ( vMap1.Extent() == 1 ) { - InsertAssociation( vMap1(1), vMap2(1), theMap, bidirect); + InsertAssociation( vMap1(1), vMap2(1), theMap ); if ( theShape1.ShapeType() == TopAbs_EDGE ) { - InsertAssociation( theShape1, theShape2, theMap, bidirect ); + InsertAssociation( theShape1, theShape2, theMap ); return true; } return FindSubShapeAssociation( theShape1, theMesh1, theShape2, theMesh2, theMap); } + // Try to associate by common vertices of an edge + for ( int i = 1; i <= vMap1.Extent(); ++i ) + { + const TopoDS_Shape& v1 = vMap1(i); + if ( vMap2.Contains( v1 )) + { + // find an egde sharing v1 and sharing at the same time another common vertex + PShapeIteratorPtr edgeIt = SMESH_MesherHelper::GetAncestors( v1, *theMesh1, TopAbs_EDGE); + bool edgeFound = false; + while ( edgeIt->more() && !edgeFound ) + { + TopoDS_Edge edge = TopoDS::Edge( edgeIt->next()->Oriented(TopAbs_FORWARD)); + TopExp::Vertices(edge, VV1[0], VV1[1]); + if ( !VV1[0].IsSame( VV1[1] )) + edgeFound = ( vMap2.Contains( VV1[ v1.IsSame(VV1[0]) ? 1:0])); + } + if ( edgeFound ) + { + InsertAssociation( VV1[0], VV1[0], theMap ); + InsertAssociation( VV1[1], VV1[1], theMap ); + if (FindSubShapeAssociation( theShape1, theMesh1, theShape2, theMesh2, theMap )) + return true; + } + } + } + // Find transformation to make the shapes be of similar size at same location Bnd_Box box[2]; - for ( int i = 1; i <= vMap1.Extent(); ++i ) { + for ( int i = 1; i <= vMap1.Extent(); ++i ) box[ 0 ].Add( BRep_Tool::Pnt ( TopoDS::Vertex( vMap1( i )))); + for ( int i = 1; i <= vMap2.Extent(); ++i ) box[ 1 ].Add( BRep_Tool::Pnt ( TopoDS::Vertex( vMap2( i )))); - } gp_Pnt gc[2]; // box center double x0,y0,z0, x1,y1,z1; @@ -816,59 +1193,76 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the // Find 2 closest vertices - TopoDS_Vertex VV1[2], VV2[2]; // get 2 linked vertices of shape 1 not belonging to an inner wire of a face - TopoDS_Shape edge = theShape1; - TopExp_Explorer expF( theShape1, TopAbs_FACE ), expE; - if ( expF.More() ) { - for ( ; expF.More(); expF.Next() ) { - edge.Nullify(); - TopoDS_Shape wire = OuterShape( TopoDS::Face( expF.Current() ), TopAbs_WIRE ); - for ( expE.Init( wire, TopAbs_EDGE ); edge.IsNull() && expE.More(); expE.Next() ) - if ( !IsClosedEdge( TopoDS::Edge( expE.Current() ))) - edge = expE.Current(); - if ( !edge.IsNull() ) - break; - } - } else if (edge.ShapeType() != TopAbs_EDGE) { // no faces - edge.Nullify(); - for ( expE.Init( theShape1, TopAbs_EDGE ); edge.IsNull() && expE.More(); expE.Next() ) - if ( !IsClosedEdge( TopoDS::Edge( expE.Current() ))) - edge = expE.Current(); - } - if ( edge.IsNull() || edge.ShapeType() != TopAbs_EDGE ) + std::list< TopoDS_Edge > allBndEdges1; + if ( !getOuterEdges( theShape1, *theMesh1, allBndEdges1 )) RETURN_BAD_RESULT("Edge not found"); - TopExp::Vertices( TopoDS::Edge( edge ), VV1[0], VV1[1]); - if ( VV1[0].IsSame( VV1[1] )) - RETURN_BAD_RESULT("Only closed edges"); - - // find vertices closest to 2 linked vertices of shape 1 - for ( int i1 = 0; i1 < 2; ++i1 ) + std::list< TopoDS_Edge >::iterator edge1 = allBndEdges1.begin(); + double minDist = std::numeric_limits::max(); + for ( int nbChecked=0; edge1 != allBndEdges1.end() && nbChecked++ < 10; ++edge1 ) { - double dist2 = DBL_MAX; - gp_Pnt p1 = BRep_Tool::Pnt( VV1[ i1 ]); - p1.Translate( vec01 ); - p1.Scale( gc[1], scale ); - for ( int i2 = 1; i2 <= vMap2.Extent(); ++i2 ) + TopExp::Vertices( TopoDS::Edge( edge1->Oriented(TopAbs_FORWARD)), VV1[0], VV1[1]); + if ( VV1[0].IsSame( VV1[1] )) + continue;//RETURN_BAD_RESULT("Only closed edges"); + + // find vertices closest to 2 linked vertices of shape 1 + double dist2[2] = { 1e+100, 1e+100 }; + TopoDS_Vertex edge2VV[2]; + for ( int i1 = 0; i1 < 2; ++i1 ) { - TopoDS_Vertex V2 = TopoDS::Vertex( vMap2( i2 )); - gp_Pnt p2 = BRep_Tool::Pnt ( V2 ); - double d2 = p1.SquareDistance( p2 ); - if ( d2 < dist2 && !V2.IsSame( VV2[ 0 ])) { - VV2[ i1 ] = V2; dist2 = d2; + gp_Pnt p1 = BRep_Tool::Pnt( VV1[ i1 ]); + p1.Scale( gc[0], scale ); + p1.Translate( vec01 ); + if ( !i1 ) { + // select a closest vertex among all ones in vMap2 + for ( int i2 = 1; i2 <= vMap2.Extent(); ++i2 ) + { + TopoDS_Vertex V2 = TopoDS::Vertex( vMap2( i2 )); + gp_Pnt p2 = BRep_Tool::Pnt ( V2 ); + double d2 = p1.SquareDistance( p2 ); + if ( d2 < dist2[ 0 ] && d2 < minDist ) { + edge2VV[ 0 ] = V2; + dist2 [ 0 ] = d2; + } + } + } + else if ( !edge2VV[0].IsNull() ) { + // select a closest vertex among ends of edges meeting at edge2VV[0] + PShapeIteratorPtr edgeIt = SMESH_MesherHelper::GetAncestors( edge2VV[0], + *theMesh2, TopAbs_EDGE); + while ( const TopoDS_Shape* edge2 = edgeIt->next() ) + for ( TopoDS_Iterator itV2( *edge2 ); itV2.More(); itV2.Next() ) + { + if ( itV2.Value().IsSame( edge2VV[ 0 ])) continue; + if ( !vMap2.Contains( itV2.Value() )) continue; + TopoDS_Vertex V2 = TopoDS::Vertex( itV2.Value() ); + gp_Pnt p2 = BRep_Tool::Pnt ( V2 ); + double d2 = p1.SquareDistance( p2 ); + if ( d2 < dist2[1] && d2 < minDist ) { + edge2VV[ 1 ] = V2; + dist2 [ 1 ] = d2; + } + } } } + if ( dist2[0] + dist2[1] < minDist ) { + VV2[0] = edge2VV[0]; + VV2[1] = edge2VV[1]; + minDist = dist2[0] + dist2[1]; + if ( minDist < 1e-10 ) + break; + } } - InsertAssociation( VV1[ 0 ], VV2[ 0 ], theMap, bidirect); - InsertAssociation( VV1[ 1 ], VV2[ 1 ], theMap, bidirect); + InsertAssociation( VV1[ 0 ], VV2[ 0 ], theMap ); + InsertAssociation( VV1[ 1 ], VV2[ 1 ], theMap ); MESSAGE("Initial assoc VERT " << theMesh1->GetMeshDS()->ShapeToIndex( VV1[ 0 ] )<< " to " << theMesh2->GetMeshDS()->ShapeToIndex( VV2[ 0 ] )<< "\nand VERT " << theMesh1->GetMeshDS()->ShapeToIndex( VV1[ 1 ] )<< " to " << theMesh2->GetMeshDS()->ShapeToIndex( VV2[ 1 ] )); if ( theShape1.ShapeType() == TopAbs_EDGE ) { - InsertAssociation( theShape1, theShape2, theMap, bidirect ); + InsertAssociation( theShape1, theShape2, theMap ); return true; } @@ -876,80 +1270,214 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the } //================================================================================ -/*! - * \brief Find association of edges of faces - * \param face1 - face 1 - * \param VV1 - vertices of face 1 - * \param face2 - face 2 - * \param VV2 - vertices of face 2 associated with oned of face 1 - * \param edges1 - out list of edges of face 1 - * \param edges2 - out list of edges of face 2 - * \retval int - nb of edges in an outer wire in a success case, else zero +/* + * Find association of edges of faces + * \param face1 - face 1 + * \param VV1 - vertices of face 1 + * \param face2 - face 2 + * \param VV2 - vertices of face 2 associated with ones of face 1 + * \param edges1 - out list of edges of face 1 + * \param edges2 - out list of edges of face 2 + * \retval int - nb of edges in an outer wire in a success case, else zero */ //================================================================================ -int StdMeshers_ProjectionUtils::FindFaceAssociation(const TopoDS_Face& face1, - TopoDS_Vertex VV1[2], - const TopoDS_Face& face2, - TopoDS_Vertex VV2[2], +int StdMeshers_ProjectionUtils::FindFaceAssociation(const TopoDS_Face& face1, + TopoDS_Vertex VV1[2], + const TopoDS_Face& face2, + TopoDS_Vertex VV2[2], list< TopoDS_Edge > & edges1, list< TopoDS_Edge > & edges2) { - edges1.clear(); - edges2.clear(); - - list< int > nbVInW1, nbVInW2; - if ( SMESH_Block::GetOrderedEdges( face1, VV1[0], edges1, nbVInW1) != - SMESH_Block::GetOrderedEdges( face2, VV2[0], edges2, nbVInW2) ) - RETURN_BAD_RESULT("Different number of wires in faces "); - - if ( nbVInW1.front() != nbVInW2.front() ) - RETURN_BAD_RESULT("Different number of edges in faces: " << - nbVInW1.front() << " != " << nbVInW2.front()); - - // Define if we need to reverse one of wires to make edges in lists match each other - - bool reverse = false; - - list< TopoDS_Edge >::iterator eBackIt; - if ( !VV1[1].IsSame( TopExp::LastVertex( edges1.front(), true ))) { - reverse = true; - eBackIt = --edges1.end(); - // check if the second vertex belongs to the first or last edge in the wire - if ( !VV1[1].IsSame( TopExp::FirstVertex( *eBackIt, true ))) { - bool KO = true; // belongs to none - if ( nbVInW1.size() > 1 ) { // several wires - eBackIt = edges1.begin(); - for ( int i = 1; i < nbVInW1.front(); ++i ) ++eBackIt; - KO = !VV1[1].IsSame( TopExp::FirstVertex( *eBackIt, true )); + bool OK = false; + list< int > nbEInW1, nbEInW2; + list< TopoDS_Edge >::iterator edgeIt; + int i_ok_wire_algo = -1; + for ( int outer_wire_algo = 0; outer_wire_algo < 2 && !OK; ++outer_wire_algo ) + { + edges1.clear(); + edges2.clear(); + + if ( SMESH_Block::GetOrderedEdges( face1, edges1, nbEInW1, VV1[0], outer_wire_algo) != + SMESH_Block::GetOrderedEdges( face2, edges2, nbEInW2, VV2[0], outer_wire_algo) ) + CONT_BAD_RESULT("Different number of wires in faces "); + + if ( nbEInW1 != nbEInW2 && outer_wire_algo == 0 && + ( std::accumulate( nbEInW1.begin(), nbEInW1.end(), 0) != + std::accumulate( nbEInW2.begin(), nbEInW2.end(), 0))) + RETURN_BAD_RESULT("Different number of edges in faces"); + + if ( nbEInW1.front() != nbEInW2.front() ) + CONT_BAD_RESULT("Different number of edges in the outer wire: " << + nbEInW1.front() << " != " << nbEInW2.front()); + + i_ok_wire_algo = outer_wire_algo; + + // Define if we need to reverse one of wires to make edges in lists match each other + + bool reverse = false; + + if ( !VV1[1].IsSame( TopExp::LastVertex( edges1.front(), true ))) { + reverse = true; + edgeIt = --edges1.end(); + // check if the second vertex belongs to the first or last edge in the wire + if ( !VV1[1].IsSame( TopExp::FirstVertex( *edgeIt, true ))) { + bool KO = true; // belongs to none + if ( nbEInW1.size() > 1 ) { // several wires + edgeIt = edges1.begin(); + std::advance( edgeIt, nbEInW1.front()-1 ); + KO = !VV1[1].IsSame( TopExp::FirstVertex( *edgeIt, true )); + } + if ( KO ) + CONT_BAD_RESULT("GetOrderedEdges() failed"); } - if ( KO ) - RETURN_BAD_RESULT("GetOrderedEdges() failed"); } - } - eBackIt = --edges2.end(); - if ( !VV2[1].IsSame( TopExp::LastVertex( edges2.front(), true ))) { - reverse = !reverse; - // check if the second vertex belongs to the first or last edge in the wire - if ( !VV2[1].IsSame( TopExp::FirstVertex( *eBackIt, true ))) { - bool KO = true; // belongs to none - if ( nbVInW2.size() > 1 ) { // several wires - eBackIt = edges2.begin(); - for ( int i = 1; i < nbVInW2.front(); ++i ) ++eBackIt; - KO = !VV2[1].IsSame( TopExp::FirstVertex( *eBackIt, true )); + if ( !VV2[1].IsSame( TopExp::LastVertex( edges2.front(), true ))) { + reverse = !reverse; + edgeIt = --edges2.end(); + // move a degenerated edge from back to front + // http://www.salome-platform.org/forum/forum_11/173031193 + if ( TopExp::FirstVertex( *edgeIt ).IsSame( TopExp::LastVertex( *edgeIt ))) { + edges2.splice( edges2.begin(), edges2, edgeIt ); + edgeIt = --edges2.end(); + } + // check if the second vertex belongs to the first or last edge in the wire + if ( !VV2[1].IsSame( TopExp::FirstVertex( *edgeIt, true ))) { + bool KO = true; // belongs to none + if ( nbEInW2.size() > 1 ) { // several wires + edgeIt = edges2.begin(); + std::advance( edgeIt, nbEInW2.front()-1 ); + KO = !VV2[1].IsSame( TopExp::FirstVertex( *edgeIt, true )); + } + if ( KO ) + CONT_BAD_RESULT("GetOrderedEdges() failed"); + } + } + if ( reverse ) + { + Reverse( edges2 , nbEInW2.front()); + if (( VV1[1].IsSame( TopExp::LastVertex( edges1.front(), true ))) != + ( VV2[1].IsSame( TopExp::LastVertex( edges2.front(), true )))) + CONT_BAD_RESULT("GetOrderedEdges() failed"); + } + OK = true; + + } // loop algos getting an outer wire + + // Try to orient all (if !OK) or only internal wires (issue 0020996) by UV similarity + + if (( !OK || nbEInW1.size() > 1 ) && i_ok_wire_algo > -1 ) + { + // Check that Vec(VV1[0],VV1[1]) in 2D on face1 is the same + // as Vec(VV2[0],VV2[1]) on face2 + double vTol = BRep_Tool::Tolerance( VV1[0] ); + BRepAdaptor_Surface surface1( face1, false ); + double vTolUV = + surface1.UResolution( vTol ) + surface1.VResolution( vTol ); // let's be tolerant + gp_Pnt2d v0f1UV = BRep_Tool::Parameters( VV1[0], face1 ); + gp_Pnt2d v0f2UV = BRep_Tool::Parameters( VV2[0], face2 ); + gp_Pnt2d v1f1UV = BRep_Tool::Parameters( VV1[1], face1 ); + gp_Pnt2d v1f2UV = BRep_Tool::Parameters( VV2[1], face2 ); + gp_Vec2d v01f1Vec( v0f1UV, v1f1UV ); + gp_Vec2d v01f2Vec( v0f2UV, v1f2UV ); + if ( Abs( v01f1Vec.X()-v01f2Vec.X()) < vTolUV && + Abs( v01f1Vec.Y()-v01f2Vec.Y()) < vTolUV ) + { + if ( !OK /*i_ok_wire_algo != 1*/ ) + { + edges1.clear(); + edges2.clear(); + SMESH_Block::GetOrderedEdges( face1, edges1, nbEInW1, VV1[0], i_ok_wire_algo); + SMESH_Block::GetOrderedEdges( face2, edges2, nbEInW2, VV2[0], i_ok_wire_algo); + } + gp_XY dUV = v0f2UV.XY() - v0f1UV.XY(); // UV shift between 2 faces + // + // skip edges of the outer wire (if the outer wire is OK) + list< int >::iterator nbE2, nbE1 = nbEInW1.begin(); + list< TopoDS_Edge >::iterator edge2Beg, edge1Beg = edges1.begin(); + if ( OK ) std::advance( edge1Beg, *nbE1++ ); + // reach an end of edges of a current wire1 + list< TopoDS_Edge >::iterator edge2End, edge1End; + // + // find corresponding wires of face2 + for ( int iW1 = OK; nbE1 != nbEInW1.end(); ++nbE1, ++iW1 ) // loop on wires of face1 + { + // reach an end of edges of a current wire1 + edge1End = edge1Beg; + std::advance( edge1End, *nbE1 ); + // UV on face1 to find on face2 + v0f1UV = BRep_Tool::Parameters( TopExp::FirstVertex(*edge1Beg,true), face1 ); + v1f1UV = BRep_Tool::Parameters( TopExp::LastVertex (*edge1Beg,true), face1 ); + v0f1UV.ChangeCoord() += dUV; + v1f1UV.ChangeCoord() += dUV; + // + // look through wires of face2 + edge2Beg = edges2.begin(); + nbE2 = nbEInW2.begin(); + if ( OK ) std::advance( edge2Beg, *nbE2++ ); + for ( int iW2 = OK; nbE2 != nbEInW2.end(); ++nbE2, ++iW2 ) // loop on wires of face2 + { + // reach an end of edges of a current wire2 + edge2End = edge2Beg; + std::advance( edge2End, *nbE2 ); + if ( *nbE1 == *nbE2 && iW2 >= iW1 ) + { + // rotate edge2 untill coincidence with edge1 in 2D + int i = *nbE2; + while ( i-- > 0 && !sameVertexUV( *edge2Beg, face2, 0, v0f1UV, vTolUV )) + // move edge2Beg to place before edge2End + edges2.splice( edge2End, edges2, edge2Beg++ ); + + if ( edge2Beg != edges2.end() && + sameVertexUV( *edge2Beg, face2, 0, v0f1UV, vTolUV )) + { + if ( iW1 == 0 ) OK = true; // OK is for the first wire + // reverse edges2 if needed + if ( !sameVertexUV( *edge2Beg, face2, 1, v1f1UV, vTolUV )) + Reverse( edges2 , *nbE2, std::distance( edges2.begin(),edge2Beg )); + // put wire2 at a right place within edges2 + if ( iW1 != iW2 ) { + list< TopoDS_Edge >::iterator place2 = edges2.begin(); + std::advance( place2, std::distance( edges1.begin(), edge1Beg )); + edges2.splice( place2, edges2, edge2Beg, edge2End ); + // move nbE2 as well + list< int >::iterator placeNbE2 = nbEInW2.begin(); + std::advance( placeNbE2, iW1 ); + nbEInW2.splice( placeNbE2, nbEInW2, nbE2 ); + } + break; + } + } + // prepare to the next wire loop + edge2Beg = edge2End; + } + edge1Beg = edge1End; } - if ( KO ) - RETURN_BAD_RESULT("GetOrderedEdges() failed"); } } - if ( reverse ) + + const int nbEdges = nbEInW1.front(); + if ( OK && nbEdges == 2 ) { - Reverse( edges2 , nbVInW2.front()); - if (( VV1[1].IsSame( TopExp::LastVertex( edges1.front(), true ))) != - ( VV2[1].IsSame( TopExp::LastVertex( edges2.front(), true )))) - RETURN_BAD_RESULT("GetOrderedEdges() failed"); + // if wires include 2 edges, it's impossible to associate them using + // topological information only. Try to use length of edges for association. + double l1[2], l2[2]; + edgeIt = edges1.begin(); + l1[0] = SMESH_Algo::EdgeLength( *edgeIt++ ); + l1[1] = SMESH_Algo::EdgeLength( *edgeIt++ ); + if ( Abs( l1[0] - l1[1] ) > 0.1 * Max( l1[0], l1[1] ) ) + { + edgeIt = edges2.begin(); + l2[0] = SMESH_Algo::EdgeLength( *edgeIt++ ); + l2[1] = SMESH_Algo::EdgeLength( *edgeIt++ ); + if (( l1[0] < l1[1] ) != ( l2[0] < l2[1] )) + { + Reverse( edges2, nbEdges ); + } + } } - return nbVInW2.front(); + + return OK ? nbEInW1.front() : 0; } //======================================================================= @@ -958,55 +1486,51 @@ int StdMeshers_ProjectionUtils::FindFaceAssociation(const TopoDS_Face& face1, //======================================================================= void StdMeshers_ProjectionUtils::InitVertexAssociation( const SMESH_Hypothesis* theHyp, - TShapeShapeMap & theAssociationMap, - const TopoDS_Shape& theTargetShape) + TShapeShapeMap & theAssociationMap) { string hypName = theHyp->GetName(); if ( hypName == "ProjectionSource1D" ) { const StdMeshers_ProjectionSource1D * hyp = static_cast( theHyp ); if ( hyp->HasVertexAssociation() ) - InsertAssociation( hyp->GetSourceVertex(),hyp->GetTargetVertex(),theAssociationMap); + InsertAssociation( hyp->GetTargetVertex(),hyp->GetSourceVertex(),theAssociationMap ); } else if ( hypName == "ProjectionSource2D" ) { const StdMeshers_ProjectionSource2D * hyp = static_cast( theHyp ); if ( hyp->HasVertexAssociation() ) { - InsertAssociation( hyp->GetSourceVertex(1),hyp->GetTargetVertex(1),theAssociationMap); - InsertAssociation( hyp->GetSourceVertex(2),hyp->GetTargetVertex(2),theAssociationMap); + InsertAssociation( hyp->GetTargetVertex(1),hyp->GetSourceVertex(1),theAssociationMap); + InsertAssociation( hyp->GetTargetVertex(2),hyp->GetSourceVertex(2),theAssociationMap); } } else if ( hypName == "ProjectionSource3D" ) { const StdMeshers_ProjectionSource3D * hyp = static_cast( theHyp ); if ( hyp->HasVertexAssociation() ) { - InsertAssociation( hyp->GetSourceVertex(1),hyp->GetTargetVertex(1),theAssociationMap); - InsertAssociation( hyp->GetSourceVertex(2),hyp->GetTargetVertex(2),theAssociationMap); + InsertAssociation( hyp->GetTargetVertex(1),hyp->GetSourceVertex(1),theAssociationMap); + InsertAssociation( hyp->GetTargetVertex(2),hyp->GetSourceVertex(2),theAssociationMap); } } } //======================================================================= -/*! - * \brief Inserts association theShape1 <-> theShape2 to TShapeShapeMap - * \param theShape1 - shape 1 - * \param theShape2 - shape 2 - * \param theAssociationMap - association map - * \retval bool - true if there was no association for these shapes before +/* + * Inserts association theShape1 <-> theShape2 to TShapeShapeMap + * \param theShape1 - target shape + * \param theShape2 - source shape + * \param theAssociationMap - association map + * \retval bool - true if there was no association for these shapes before */ //======================================================================= -bool StdMeshers_ProjectionUtils::InsertAssociation( const TopoDS_Shape& theShape1, - const TopoDS_Shape& theShape2, - TShapeShapeMap & theAssociationMap, - const bool theBidirectional) +bool StdMeshers_ProjectionUtils::InsertAssociation( const TopoDS_Shape& theShape1, // tgt + const TopoDS_Shape& theShape2, // src + TShapeShapeMap & theAssociationMap) { if ( !theShape1.IsNull() && !theShape2.IsNull() ) { - SHOW_VERTEX(theShape1,"Assoc "); - SHOW_VERTEX(theShape2," to "); + SHOW_SHAPE(theShape1,"Assoc "); + SHOW_SHAPE(theShape2," to "); bool isNew = ( theAssociationMap.Bind( theShape1, theShape2 )); - if ( theBidirectional ) - theAssociationMap.Bind( theShape2, theShape1 ); return isNew; } else { @@ -1016,50 +1540,12 @@ bool StdMeshers_ProjectionUtils::InsertAssociation( const TopoDS_Shape& theShape } //======================================================================= -//function : IsSubShape -//purpose : -//======================================================================= - -bool StdMeshers_ProjectionUtils::IsSubShape( const TopoDS_Shape& shape, - SMESH_Mesh* aMesh ) -{ - if ( shape.IsNull() || !aMesh ) - return false; - return - aMesh->GetMeshDS()->ShapeToIndex( shape ) || - // PAL16202 - shape.ShapeType() == TopAbs_COMPOUND && aMesh->GetMeshDS()->IsGroupOfSubShapes( shape ); -} - -//======================================================================= -//function : IsSubShape -//purpose : -//======================================================================= - -bool StdMeshers_ProjectionUtils::IsSubShape( const TopoDS_Shape& shape, - const TopoDS_Shape& mainShape ) -{ - if ( !shape.IsNull() && !mainShape.IsNull() ) - { - for ( TopExp_Explorer exp( mainShape, shape.ShapeType()); - exp.More(); - exp.Next() ) - if ( shape.IsSame( exp.Current() )) - return true; - } - SCRUTE((shape.IsNull())); - SCRUTE((mainShape.IsNull())); - return false; -} - - -//======================================================================= -/*! - * \brief Finds an edge by its vertices in a main shape of the mesh - * \param aMesh - the mesh - * \param V1 - vertex 1 - * \param V2 - vertex 2 - * \retval TopoDS_Edge - found edge +/* + * Finds an edge by its vertices in a main shape of the mesh + * \param aMesh - the mesh + * \param V1 - vertex 1 + * \param V2 - vertex 2 + * \retval TopoDS_Edge - found edge */ //======================================================================= @@ -1082,12 +1568,12 @@ TopoDS_Edge StdMeshers_ProjectionUtils::GetEdgeByVertices( SMESH_Mesh* } //================================================================================ -/*! - * \brief Return another face sharing an edge - * \param edgeToFaces - data map of descendants to ancestors - * \param edge - edge - * \param face - face - * \retval TopoDS_Face - found face +/* + * Return another face sharing an edge + * \param edgeToFaces - data map of descendants to ancestors + * \param edge - edge + * \param face - face + * \retval TopoDS_Face - found face */ //================================================================================ @@ -1108,8 +1594,8 @@ TopoDS_Face StdMeshers_ProjectionUtils::GetNextFace( const TAncestorMap& edgeToF } //================================================================================ -/*! - * \brief Return other vertex of an edge +/* + * Return other vertex of an edge */ //================================================================================ @@ -1124,82 +1610,90 @@ TopoDS_Vertex StdMeshers_ProjectionUtils::GetNextVertex(const TopoDS_Edge& edg } //================================================================================ -/*! - * \brief Return a propagation edge - * \param aMesh - mesh - * \param theEdge - edge to find by propagation - * \param fromEdge - start edge for propagation - * \retval pair - propagation step and found edge +/* + * Return a propagation edge + * \param aMesh - mesh + * \param anEdge - edge to find by propagation + * \param fromEdge - start edge for propagation + * \param chain - return, if !NULL, a propagation chain passed till + * anEdge; if anEdge.IsNull() then a full propagation chain is returned; + * fromEdge is the 1st in the chain + * \retval pair - propagation step and found edge */ //================================================================================ pair -StdMeshers_ProjectionUtils::GetPropagationEdge( SMESH_Mesh* aMesh, - const TopoDS_Edge& theEdge, - const TopoDS_Edge& fromEdge) +StdMeshers_ProjectionUtils::GetPropagationEdge( SMESH_Mesh* aMesh, + const TopoDS_Edge& anEdge, + const TopoDS_Edge& fromEdge, + TopTools_IndexedMapOfShape* chain) { - SMESH_IndexedMapOfShape aChain; + TopTools_IndexedMapOfShape locChain; + TopTools_IndexedMapOfShape& aChain = chain ? *chain : locChain; int step = 0; + //TopTools_IndexedMapOfShape checkedWires; + BRepTools_WireExplorer aWE; + TopoDS_Shape fourEdges[4]; + // List of edges, added to chain on the previous cycle pass TopTools_ListOfShape listPrevEdges; - listPrevEdges.Append(fromEdge); + listPrevEdges.Append( fromEdge ); + aChain.Add( fromEdge ); // Collect all edges pass by pass - while (listPrevEdges.Extent() > 0) { + while (listPrevEdges.Extent() > 0) + { step++; // List of edges, added to chain on this cycle pass TopTools_ListOfShape listCurEdges; // Find the next portion of edges TopTools_ListIteratorOfListOfShape itE (listPrevEdges); - for (; itE.More(); itE.Next()) { - TopoDS_Shape anE = itE.Value(); + for (; itE.More(); itE.Next()) + { + const TopoDS_Shape& anE = itE.Value(); // Iterate on faces, having edge TopTools_ListIteratorOfListOfShape itA (aMesh->GetAncestors(anE)); - for (; itA.More(); itA.Next()) { - TopoDS_Shape aW = itA.Value(); + for (; itA.More(); itA.Next()) + { + const TopoDS_Shape& aW = itA.Value(); // There are objects of different type among the ancestors of edge - if (aW.ShapeType() == TopAbs_WIRE) { - TopoDS_Shape anOppE; - - BRepTools_WireExplorer aWE (TopoDS::Wire(aW)); - Standard_Integer nb = 1, found = 0; - TopTools_Array1OfShape anEdges (1,4); - for (; aWE.More(); aWE.Next(), nb++) { - if (nb > 4) { - found = 0; + if ( aW.ShapeType() == TopAbs_WIRE /*&& checkedWires.Add( aW )*/) + { + Standard_Integer nb = 0, found = -1; + for ( aWE.Init( TopoDS::Wire( aW )); aWE.More(); aWE.Next() ) { + if (nb+1 > 4) { + found = -1; break; } - anEdges(nb) = aWE.Current(); - if (anEdges(nb).IsSame(anE)) found = nb; + fourEdges[ nb ] = aWE.Current(); + if ( aWE.Current().IsSame( anE )) found = nb; + nb++; } - - if (nb == 5 && found > 0) { + if (nb == 4 && found >= 0) { // Quadrangle face found, get an opposite edge - Standard_Integer opp = found + 2; - if (opp > 4) opp -= 4; - anOppE = anEdges(opp); + TopoDS_Shape& anOppE = fourEdges[( found + 2 ) % 4 ]; // add anOppE to aChain if ... - if (!aChain.Contains(anOppE)) { // ... anOppE is not in aChain + int prevChainSize = aChain.Extent(); + if ( aChain.Add(anOppE) > prevChainSize ) { // ... anOppE is not in aChain // Add found edge to the chain oriented so that to // have it co-directed with a forward MainEdge TopAbs_Orientation ori = anE.Orientation(); - if ( anEdges(opp).Orientation() == anEdges(found).Orientation() ) + if ( anOppE.Orientation() == fourEdges[found].Orientation() ) ori = TopAbs::Reverse( ori ); anOppE.Orientation( ori ); - if ( anOppE.IsSame( theEdge )) + if ( anOppE.IsSame( anEdge )) return make_pair( step, TopoDS::Edge( anOppE )); - aChain.Add(anOppE); listCurEdges.Append(anOppE); } - } // if (nb == 5 && found > 0) + } // if (nb == 4 && found >= 0) } // if (aF.ShapeType() == TopAbs_WIRE) - } // for (; itF.More(); itF.Next()) - } // for (; itE.More(); itE.Next()) + } // loop on ancestors of anE + } // loop on listPrevEdges listPrevEdges = listCurEdges; } // while (listPrevEdges.Extent() > 0) @@ -1208,16 +1702,16 @@ StdMeshers_ProjectionUtils::GetPropagationEdge( SMESH_Mesh* aMesh, } //================================================================================ - /*! - * \brief Find corresponding nodes on two faces - * \param face1 - the first face - * \param mesh1 - mesh containing elements on the first face - * \param face2 - the second face - * \param mesh2 - mesh containing elements on the second face - * \param assocMap - map associating subshapes of the faces - * \param node1To2Map - map containing found matching nodes - * \retval bool - is a success - */ +/* + * Find corresponding nodes on two faces + * \param face1 - the first face + * \param mesh1 - mesh containing elements on the first face + * \param face2 - the second face + * \param mesh2 - mesh containing elements on the second face + * \param assocMap - map associating sub-shapes of the faces + * \param node1To2Map - map containing found matching nodes + * \retval bool - is a success + */ //================================================================================ bool StdMeshers_ProjectionUtils:: @@ -1230,7 +1724,7 @@ FindMatchingNodesOnFaces( const TopoDS_Face& face1, { SMESHDS_Mesh* meshDS1 = mesh1->GetMeshDS(); SMESHDS_Mesh* meshDS2 = mesh2->GetMeshDS(); - + SMESH_MesherHelper helper1( *mesh1 ); SMESH_MesherHelper helper2( *mesh2 ); @@ -1258,24 +1752,25 @@ FindMatchingNodesOnFaces( const TopoDS_Face& face1, // 1. Nodes of corresponding links: // get 2 matching edges, try to find not seam ones - TopoDS_Edge edge1, edge2, seam1, seam2; + TopoDS_Edge edge1, edge2, seam1, seam2, anyEdge1, anyEdge2; TopExp_Explorer eE( OuterShape( face2, TopAbs_WIRE ), TopAbs_EDGE ); do { // edge 2 TopoDS_Edge e2 = TopoDS::Edge( eE.Current() ); eE.Next(); // edge 1 - if ( !assocMap.IsBound( e2 )) + if ( !assocMap.IsBound( e2, /*is2nd=*/true )) RETURN_BAD_RESULT("Association not found for edge " << meshDS2->ShapeToIndex( e2 )); - TopoDS_Edge e1 = TopoDS::Edge( assocMap( e2 )); - if ( !IsSubShape( e1, face1 )) + TopoDS_Edge e1 = TopoDS::Edge( assocMap( e2, /*is2nd=*/true )); + if ( !helper1.IsSubShape( e1, face1 )) RETURN_BAD_RESULT("Wrong association, edge " << meshDS1->ShapeToIndex( e1 ) << - " isn't a subshape of face " << meshDS1->ShapeToIndex( face1 )); + " isn't a sub-shape of face " << meshDS1->ShapeToIndex( face1 )); // check that there are nodes on edges SMESHDS_SubMesh * eSM1 = meshDS1->MeshElements( e1 ); SMESHDS_SubMesh * eSM2 = meshDS2->MeshElements( e2 ); bool nodesOnEdges = ( eSM1 && eSM2 && eSM1->NbNodes() && eSM2->NbNodes() ); // check that the nodes on edges belong to faces + // (as NETGEN ignores nodes on the degenerated geom edge) bool nodesOfFaces = false; if ( nodesOnEdges ) { const SMDS_MeshNode* n1 = eSM1->GetNodes()->next(); @@ -1285,25 +1780,32 @@ FindMatchingNodesOnFaces( const TopoDS_Face& face1, } if ( nodesOfFaces ) { - if ( BRep_Tool::IsClosed( e2, face2 )) { + if ( helper2.IsRealSeam( e2 )) { seam1 = e1; seam2 = e2; } else { edge1 = e1; edge2 = e2; } } + else { + anyEdge1 = e1; anyEdge2 = e2; + } } while ( edge2.IsNull() && eE.More() ); // if ( edge2.IsNull() ) { edge1 = seam1; edge2 = seam2; } - if ( edge2.IsNull() ) RETURN_BAD_RESULT("No matching edges with nodes found"); + bool hasNodesOnEdge = (! edge2.IsNull() ); + if ( !hasNodesOnEdge ) { + // 0020338 - nb segments == 1 + edge1 = anyEdge1; edge2 = anyEdge2; + } // get 2 matching vertices TopoDS_Vertex V2 = TopExp::FirstVertex( TopoDS::Edge( edge2 )); - if ( !assocMap.IsBound( V2 )) + if ( !assocMap.IsBound( V2, /*is2nd=*/true )) RETURN_BAD_RESULT("Association not found for vertex " << meshDS2->ShapeToIndex( V2 )); - TopoDS_Vertex V1 = TopoDS::Vertex( assocMap( V2 )); + TopoDS_Vertex V1 = TopoDS::Vertex( assocMap( V2, /*is2nd=*/true )); // nodes on vertices const SMDS_MeshNode* vNode1 = SMESH_Algo::VertexNode( V1, meshDS1 ); @@ -1315,35 +1817,52 @@ FindMatchingNodesOnFaces( const TopoDS_Face& face1, const SMDS_MeshNode* nullNode = 0; vector< const SMDS_MeshNode*> eNode1( 2, nullNode ); vector< const SMDS_MeshNode*> eNode2( 2, nullNode ); - int nbNodeToGet = 1; - if ( IsClosedEdge( edge1 ) || IsClosedEdge( edge2 ) ) - nbNodeToGet = 2; - for ( int is2 = 0; is2 < 2; ++is2 ) + if ( hasNodesOnEdge ) { - TopoDS_Edge & edge = is2 ? edge2 : edge1; - SMESHDS_Mesh * smDS = is2 ? meshDS2 : meshDS1; - SMESHDS_SubMesh* edgeSM = smDS->MeshElements( edge ); - // nodes linked with ones on vertices - const SMDS_MeshNode* vNode = is2 ? vNode2 : vNode1; - vector< const SMDS_MeshNode*>& eNode = is2 ? eNode2 : eNode1; - int nbGotNode = 0; - SMDS_ElemIteratorPtr vElem = vNode->GetInverseElementIterator(); - while ( vElem->more() && nbGotNode != nbNodeToGet ) { - const SMDS_MeshElement* elem = vElem->next(); - if ( elem->GetType() == SMDSAbs_Edge && edgeSM->Contains( elem )) - eNode[ nbGotNode++ ] = - ( elem->GetNode(0) == vNode ) ? elem->GetNode(1) : elem->GetNode(0); - } - if ( nbGotNode > 1 ) // sort found nodes by param on edge + int nbNodeToGet = 1; + if ( helper1.IsClosedEdge( edge1 ) || helper2.IsClosedEdge( edge2 ) ) + nbNodeToGet = 2; + for ( int is2 = 0; is2 < 2; ++is2 ) { - SMESH_MesherHelper* helper = is2 ? &helper2 : &helper1; - double u0 = helper->GetNodeU( edge, eNode[ 0 ]); - double u1 = helper->GetNodeU( edge, eNode[ 1 ]); - if ( u0 > u1 ) std::swap( eNode[ 0 ], eNode[ 1 ]); + TopoDS_Edge & edge = is2 ? edge2 : edge1; + SMESHDS_Mesh * smDS = is2 ? meshDS2 : meshDS1; + SMESHDS_SubMesh* edgeSM = smDS->MeshElements( edge ); + // nodes linked with ones on vertices + const SMDS_MeshNode* vNode = is2 ? vNode2 : vNode1; + vector< const SMDS_MeshNode*>& eNode = is2 ? eNode2 : eNode1; + int nbGotNode = 0; + SMDS_ElemIteratorPtr vElem = vNode->GetInverseElementIterator(SMDSAbs_Edge); + while ( vElem->more() && nbGotNode != nbNodeToGet ) { + const SMDS_MeshElement* elem = vElem->next(); + if ( edgeSM->Contains( elem )) + eNode[ nbGotNode++ ] = + ( elem->GetNode(0) == vNode ) ? elem->GetNode(1) : elem->GetNode(0); + } + if ( nbGotNode > 1 ) // sort found nodes by param on edge + { + SMESH_MesherHelper* helper = is2 ? &helper2 : &helper1; + double u0 = helper->GetNodeU( edge, eNode[ 0 ]); + double u1 = helper->GetNodeU( edge, eNode[ 1 ]); + if ( u0 > u1 ) std::swap( eNode[ 0 ], eNode[ 1 ]); + } + if ( nbGotNode == 0 ) + RETURN_BAD_RESULT("Found no nodes on edge " << smDS->ShapeToIndex( edge ) << + " linked to " << vNode ); } - if ( nbGotNode == 0 ) - RETURN_BAD_RESULT("Found no nodes on edge " << smDS->ShapeToIndex( edge ) << - " linked to " << vNode ); + } + else // 0020338 - nb segments == 1 + { + // get 2 other matching vertices + V2 = TopExp::LastVertex( TopoDS::Edge( edge2 )); + if ( !assocMap.IsBound( V2, /*is2nd=*/true )) + RETURN_BAD_RESULT("Association not found for vertex " << meshDS2->ShapeToIndex( V2 )); + V1 = TopoDS::Vertex( assocMap( V2, /*is2nd=*/true )); + + // nodes on vertices + eNode1[0] = SMESH_Algo::VertexNode( V1, meshDS1 ); + eNode2[0] = SMESH_Algo::VertexNode( V2, meshDS2 ); + if ( !eNode1[0] ) RETURN_BAD_RESULT("No node on vertex #" << meshDS1->ShapeToIndex( V1 )); + if ( !eNode2[0] ) RETURN_BAD_RESULT("No node on vertex #" << meshDS2->ShapeToIndex( V2 )); } // 2. face sets @@ -1357,7 +1876,7 @@ FindMatchingNodesOnFaces( const TopoDS_Face& face1, const TopoDS_Face & face = is2 ? face2 : face1; SMDS_ElemIteratorPtr eIt = sm->GetElements(); - if ( !helper->IsSeamShape( is2 ? edge2 : edge1 )) + if ( !helper->IsRealSeam( is2 ? edge2 : edge1 )) { while ( eIt->more() ) elems.insert( eIt->next() ); } @@ -1375,12 +1894,12 @@ FindMatchingNodesOnFaces( const TopoDS_Face& face1, TIDSortedElemSet inSet, notInSet; const SMDS_MeshElement* f1 = - SMESH_MeshEditor::FindFaceInSet( vNode, eNode, inSet, notInSet ); + SMESH_MeshAlgos::FindFaceInSet( vNode, eNode, inSet, notInSet ); if ( !f1 ) RETURN_BAD_RESULT("The first face on seam not found"); notInSet.insert( f1 ); const SMDS_MeshElement* f2 = - SMESH_MeshEditor::FindFaceInSet( vNode, eNode, inSet, notInSet ); + SMESH_MeshAlgos::FindFaceInSet( vNode, eNode, inSet, notInSet ); if ( !f2 ) RETURN_BAD_RESULT("The second face on seam not found"); // select a face with less UV of vNode @@ -1389,7 +1908,7 @@ FindMatchingNodesOnFaces( const TopoDS_Face& face1, const SMDS_MeshElement* f = ( iF ? f2 : f1 ); for ( int i = 0; !notSeamNode[ iF ] && i < f->NbNodes(); ++i ) { const SMDS_MeshNode* node = f->GetNode( i ); - if ( !helper->IsSeamShape( node->GetPosition()->GetShapeId() )) + if ( !helper->IsSeamShape( node->getshapeId() )) notSeamNode[ iF ] = node; } } @@ -1422,8 +1941,8 @@ FindMatchingNodesOnFaces( const TopoDS_Face& face1, notInSet.insert( f2 ); for ( int i = 0; i < nbNodes; ++i ) { const SMDS_MeshNode* n1 = faceToKeep->GetNode( i ); - const SMDS_MeshNode* n2 = faceToKeep->GetNode( i+1 ); - f1 = SMESH_MeshEditor::FindFaceInSet( n1, n2, inSet, notInSet ); + const SMDS_MeshNode* n2 = faceToKeep->GetNode(( i+1 ) % nbNodes ); + f1 = SMESH_MeshAlgos::FindFaceInSet( n1, n2, inSet, notInSet ); if ( f1 ) elems.insert( f1 ); } @@ -1442,7 +1961,7 @@ FindMatchingNodesOnFaces( const TopoDS_Face& face1, // On a sphere, add matching nodes on the edge - if ( helper1.IsSeamShape( edge1 )) + if ( helper1.IsRealSeam( edge1 )) { // sort nodes on edges by param on edge map< double, const SMDS_MeshNode* > u2nodesMaps[2]; @@ -1457,7 +1976,7 @@ FindMatchingNodesOnFaces( const TopoDS_Face& face1, while ( nIt->more() ) { const SMDS_MeshNode* node = nIt->next(); const SMDS_EdgePosition* pos = - static_cast(node->GetPosition().get()); + static_cast(node->GetPosition()); pos2nodes.insert( make_pair( pos->GetUParameter(), node )); } if ( pos2nodes.size() != edgeSM->NbNodes() ) @@ -1489,9 +2008,9 @@ FindMatchingNodesOnFaces( const TopoDS_Face& face1, // associate matching nodes on the last vertices V2 = TopExp::LastVertex( TopoDS::Edge( edge2 )); - if ( !assocMap.IsBound( V2 )) + if ( !assocMap.IsBound( V2, /*is2nd=*/true )) RETURN_BAD_RESULT("Association not found for vertex " << meshDS2->ShapeToIndex( V2 )); - V1 = TopoDS::Vertex( assocMap( V2 )); + V1 = TopoDS::Vertex( assocMap( V2, /*is2nd=*/true )); vNode1 = SMESH_Algo::VertexNode( V1, meshDS1 ); vNode2 = SMESH_Algo::VertexNode( V2, meshDS2 ); if ( !vNode1 ) RETURN_BAD_RESULT("No node on vertex #" << meshDS1->ShapeToIndex( V1 )); @@ -1499,38 +2018,25 @@ FindMatchingNodesOnFaces( const TopoDS_Face& face1, node1To2Map.insert( make_pair( vNode1, vNode2 )); } -// don't know why this condition is usually true :( -// if ( node1To2Map.size() * quadFactor < SM1->NbNodes() ) -// MESSAGE("FindMatchingNodes() found too few node pairs starting from nodes (" -// << vNode1->GetID() << " - " << eNode1[0]->GetID() << ") (" -// << vNode2->GetID() << " - " << eNode2[0]->GetID() << "):" -// << node1To2Map.size() * quadFactor << " < " << SM1->NbNodes()); - + // don't know why this condition is usually true :( + // if ( node1To2Map.size() * quadFactor < SM1->NbNodes() ) + // MESSAGE("FindMatchingNodes() found too few node pairs starting from nodes (" + // << vNode1->GetID() << " - " << eNode1[0]->GetID() << ") (" + // << vNode2->GetID() << " - " << eNode2[0]->GetID() << "):" + // << node1To2Map.size() * quadFactor << " < " << SM1->NbNodes()); + return true; } //================================================================================ -/*! - * \brief Check if the first and last vertices of an edge are the same - * \param anEdge - the edge to check - * \retval bool - true if same +/* + * Return any sub-shape of a face belonging to the outer wire + * \param face - the face + * \param type - type of sub-shape to return + * \retval TopoDS_Shape - the found sub-shape */ //================================================================================ -bool StdMeshers_ProjectionUtils::IsClosedEdge( const TopoDS_Edge& anEdge ) -{ - return TopExp::FirstVertex( anEdge ).IsSame( TopExp::LastVertex( anEdge )); -} - -//================================================================================ - /*! - * \brief Return any subshape of a face belonging to the outer wire - * \param face - the face - * \param type - type of subshape to return - * \retval TopoDS_Shape - the found subshape - */ -//================================================================================ - TopoDS_Shape StdMeshers_ProjectionUtils::OuterShape( const TopoDS_Face& face, TopAbs_ShapeEnum type) { @@ -1541,12 +2047,12 @@ TopoDS_Shape StdMeshers_ProjectionUtils::OuterShape( const TopoDS_Face& face, } //================================================================================ - /*! - * \brief Check that submesh is computed and try to compute it if is not - * \param sm - submesh to compute - * \param iterationNb - int used to stop infinite recursive call - * \retval bool - true if computed - */ +/* + * Check that sub-mesh is computed and try to compute it if is not + * \param sm - sub-mesh to compute + * \param iterationNb - int used to stop infinite recursive call + * \retval bool - true if computed + */ //================================================================================ bool StdMeshers_ProjectionUtils::MakeComputed(SMESH_subMesh * sm, const int iterationNb) @@ -1558,20 +2064,65 @@ bool StdMeshers_ProjectionUtils::MakeComputed(SMESH_subMesh * sm, const int iter if ( sm->IsMeshComputed() ) return true; - SMESH_Mesh* mesh = sm->GetFather(); - SMESH_Gen* gen = mesh->GetGen(); - SMESH_Algo* algo = gen->GetAlgo( *mesh, sm->GetSubShape() ); + SMESH_Mesh* mesh = sm->GetFather(); + SMESH_Gen* gen = mesh->GetGen(); + SMESH_Algo* algo = sm->GetAlgo(); + TopoDS_Shape shape = sm->GetSubShape(); if ( !algo ) - RETURN_BAD_RESULT("No algo assigned to submesh " << sm->GetId()); + { + if ( shape.ShapeType() != TopAbs_COMPOUND ) + { + // No algo assigned to a non-compound sub-mesh. + // Try to find an all-dimensional algo of an upper dimension + int dim = gen->GetShapeDim( shape ); + for ( ++dim; ( dim <= 3 && !algo ); ++dim ) + { + SMESH_HypoFilter hypoFilter( SMESH_HypoFilter::IsAlgo() ); + hypoFilter.And( SMESH_HypoFilter::HasDim( dim )); + list hyps; + list< TopoDS_Shape > assignedTo; + int nbAlgos = + mesh->GetHypotheses( shape, hypoFilter, hyps, true, &assignedTo ); + if ( nbAlgos > 1 ) // concurrent algos + { + list smList; // where an algo is assigned + list< TopoDS_Shape >::iterator shapeIt = assignedTo.begin(); + for ( ; shapeIt != assignedTo.end(); ++shapeIt ) + smList.push_back( mesh->GetSubMesh( *shapeIt )); + + mesh->SortByMeshOrder( smList ); + algo = smList.front()->GetAlgo(); + shape = smList.front()->GetSubShape(); + } + else if ( nbAlgos == 1 ) + { + algo = (SMESH_Algo*) hyps.front(); + shape = assignedTo.front(); + } + } + if ( !algo ) + return false; + } + else + { + // group + bool computed = true; + for ( TopoDS_Iterator grMember( shape ); grMember.More(); grMember.Next()) + if ( SMESH_subMesh* grSub = mesh->GetSubMesh( grMember.Value() )) + if ( !MakeComputed( grSub, iterationNb + 1 )) + computed = false; + return computed; + } + } string algoType = algo->GetName(); if ( algoType.substr(0, 11) != "Projection_") - return gen->Compute( *mesh, sm->GetSubShape() ); + return gen->Compute( *mesh, shape, /*shapeOnly=*/true ); // try to compute source mesh const list & hyps = - algo->GetUsedHypothesis( *mesh, sm->GetSubShape() ); + algo->GetUsedHypothesis( *mesh, shape ); TopoDS_Shape srcShape; SMESH_Mesh* srcMesh = 0; @@ -1598,44 +2149,93 @@ bool StdMeshers_ProjectionUtils::MakeComputed(SMESH_subMesh * sm, const int iter } } if ( srcShape.IsNull() ) // no projection source defined - return gen->Compute( *mesh, sm->GetSubShape() ); + return gen->Compute( *mesh, shape, /*shapeOnly=*/true ); - if ( srcShape.IsSame( sm->GetSubShape() )) + if ( srcShape.IsSame( shape )) RETURN_BAD_RESULT("Projection from self"); if ( !srcMesh ) srcMesh = mesh; - return MakeComputed( srcMesh->GetSubMesh( srcShape ), iterationNb + 1 ); + if ( MakeComputed( srcMesh->GetSubMesh( srcShape ), iterationNb + 1 ) && + gen->Compute( *mesh, shape, /*shapeOnly=*/true )) + return sm->IsMeshComputed(); + + return false; } + //================================================================================ - /*! - * \brief Count nb of subshapes - * \param shape - the shape - * \param type - the type of subshapes to count - * \retval int - the calculated number - */ +/* + * Returns an error message to show in case if MakeComputed( sm ) fails. + */ //================================================================================ -int StdMeshers_ProjectionUtils::Count(const TopoDS_Shape& shape, - const TopAbs_ShapeEnum type, - const bool ignoreSame) +std::string StdMeshers_ProjectionUtils::SourceNotComputedError( SMESH_subMesh * sm, + SMESH_Algo* projAlgo ) { - if ( ignoreSame ) { - TopTools_IndexedMapOfShape map; - TopExp::MapShapes( shape, type, map ); - return map.Extent(); - } - else { - int nb = 0; - for ( TopExp_Explorer exp( shape, type ); exp.More(); exp.Next() ) - ++nb; - return nb; + const char usualMessage [] = "Source mesh not computed"; + if ( !projAlgo ) + return usualMessage; + if ( !sm || sm->GetAlgoState() != SMESH_subMesh::NO_ALGO ) + return usualMessage; // algo is OK, anything else is KO. + + // Try to find a type of all-dimentional algorithm that would compute the + // given sub-mesh if it could be launched before projection + const TopoDS_Shape shape = sm->GetSubShape(); + const int shapeDim = SMESH_Gen::GetShapeDim( shape ); + + for ( int dimIncrement = 1; shapeDim + dimIncrement < 4; ++dimIncrement ) + { + SMESH_HypoFilter filter( SMESH_HypoFilter::IsAlgo() ); + filter.And( filter.HasDim( shapeDim + dimIncrement )); + + SMESH_Algo* algo = (SMESH_Algo*) sm->GetFather()->GetHypothesis( shape, filter, true ); + if ( algo && !algo->NeedDiscreteBoundary() ) + return SMESH_Comment("\"") + << algo->GetFeatures()._label << "\"" + << " can't be used to compute the source mesh for \"" + << projAlgo->GetFeatures()._label << "\" in this case"; } + return usualMessage; +} + +//================================================================================ +/* + * Return a boundary EDGE (or all boundary EDGEs) of edgeContainer + */ +//================================================================================ + +TopoDS_Edge StdMeshers_ProjectionUtils::GetBoundaryEdge(const TopoDS_Shape& edgeContainer, + const SMESH_Mesh& mesh, + std::list< TopoDS_Edge >* allBndEdges) +{ + TopTools_IndexedMapOfShape facesOfEdgeContainer, facesNearEdge; + TopExp::MapShapes( edgeContainer, TopAbs_FACE, facesOfEdgeContainer ); + + if ( !facesOfEdgeContainer.IsEmpty() ) + for ( TopExp_Explorer exp(edgeContainer, TopAbs_EDGE); exp.More(); exp.Next() ) + { + const TopoDS_Edge& edge = TopoDS::Edge( exp.Current() ); + facesNearEdge.Clear(); + PShapeIteratorPtr faceIt = SMESH_MesherHelper::GetAncestors( edge, mesh, TopAbs_FACE ); + while ( const TopoDS_Shape* face = faceIt->next() ) + if ( facesOfEdgeContainer.Contains( *face )) + if ( facesNearEdge.Add( *face ) && facesNearEdge.Extent() > 1 ) + break; + if ( facesNearEdge.Extent() == 1 ) { + if ( allBndEdges ) + allBndEdges->push_back( edge ); + else + return edge; + } + } + + return TopoDS_Edge(); } -namespace { + +namespace { // Definition of event listeners SMESH_subMeshEventListener* GetSrcSubMeshListener(); @@ -1648,8 +2248,8 @@ namespace { struct HypModifWaiter: SMESH_subMeshEventListener { - HypModifWaiter():SMESH_subMeshEventListener(0){} // won't be deleted by submesh - + HypModifWaiter():SMESH_subMeshEventListener(false,// won't be deleted by submesh + "StdMeshers_ProjectionUtils::HypModifWaiter") {} void ProcessEvent(const int event, const int eventType, SMESH_subMesh* subMesh, EventListenerData*, const SMESH_Hypothesis*) { @@ -1659,9 +2259,7 @@ namespace { // delete current source listener subMesh->DeleteEventListener( GetSrcSubMeshListener() ); // let algo set a new one - SMESH_Gen* gen = subMesh->GetFather()->GetGen(); - if ( SMESH_Algo* algo = gen->GetAlgo( *subMesh->GetFather(), - subMesh->GetSubShape() )) + if ( SMESH_Algo* algo = subMesh->GetAlgo() ) algo->SetEventListener( subMesh ); } } @@ -1683,17 +2281,18 @@ namespace { //================================================================================ SMESH_subMeshEventListener* GetSrcSubMeshListener() { - static SMESH_subMeshEventListener srcListener(0); // won't be deleted by submesh + static SMESH_subMeshEventListener srcListener(false, // won't be deleted by submesh + "StdMeshers_ProjectionUtils::SrcSubMeshListener"); return &srcListener; } } //================================================================================ -/*! - * \brief Set event listeners to submesh with projection algo - * \param subMesh - submesh with projection algo - * \param srcShape - source shape - * \param srcMesh - source mesh +/* + * Set event listeners to submesh with projection algo + * \param subMesh - submesh with projection algo + * \param srcShape - source shape + * \param srcMesh - source mesh */ //================================================================================ @@ -1701,8 +2300,8 @@ void StdMeshers_ProjectionUtils::SetEventListener(SMESH_subMesh* subMesh, TopoDS_Shape srcShape, SMESH_Mesh* srcMesh) { - // Set listener that resets an event listener on source submesh when - // "ProjectionSource*D" hypothesis is modified + // Set the listener that resets an event listener on source submesh when + // "ProjectionSource*D" hypothesis is modified since source shape can be changed subMesh->SetEventListener( GetHypModifWaiter(),0,subMesh); // Set an event listener to submesh of the source shape @@ -1717,18 +2316,21 @@ void StdMeshers_ProjectionUtils::SetEventListener(SMESH_subMesh* subMesh, if ( srcShapeSM->GetSubMeshDS() && srcShapeSM->GetSubMeshDS()->IsComplexSubmesh() ) { // source shape is a group - TopExp_Explorer it(srcShapeSM->GetSubShape(), // explore the group into subshapes... + TopExp_Explorer it(srcShapeSM->GetSubShape(), // explore the group into sub-shapes... subMesh->GetSubShape().ShapeType()); // ...of target shape type for (; it.More(); it.Next()) { SMESH_subMesh* srcSM = srcMesh->GetSubMesh( it.Current() ); - SMESH_subMeshEventListenerData* data = - srcSM->GetEventListenerData(GetSrcSubMeshListener()); - if ( data ) - data->mySubMeshes.push_back( subMesh ); - else - data = SMESH_subMeshEventListenerData::MakeData( subMesh ); - subMesh->SetEventListener ( GetSrcSubMeshListener(), data, srcSM ); + if ( srcSM != subMesh ) + { + SMESH_subMeshEventListenerData* data = + srcSM->GetEventListenerData(GetSrcSubMeshListener()); + if ( data ) + data->mySubMeshes.push_back( subMesh ); + else + data = SMESH_subMeshEventListenerData::MakeData( subMesh ); + subMesh->SetEventListener ( GetSrcSubMeshListener(), data, srcSM ); + } } } else