Salome HOME
win32 compilation of the Mesh module.
[modules/smesh.git] / src / StdMeshers / StdMeshers_ProjectionUtils.cxx
index 38028c2d7f4f0e7e2e92ada647baee16717ee403..bc497c74bd4268cdf820f921b0cc609e0bc9972f 100644 (file)
@@ -1,23 +1,23 @@
-//  Copyright (C) 2007-2010  CEA/DEN, EDF R&D, OPEN CASCADE
+// Copyright (C) 2007-2011  CEA/DEN, EDF R&D, OPEN CASCADE
 //
-//  Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
-//  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
+// 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.
+// 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.
+// 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
+// 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
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
 //
 
 //  SMESH SMESH : idl implementation based on 'SMESH' unit's calsses
@@ -35,7 +35,6 @@
 #include "SMESH_Block.hxx"
 #include "SMESH_Gen.hxx"
 #include "SMESH_Hypothesis.hxx"
-#include "SMESH_IndexedDataMapOfShapeIndexedMapOfShape.hxx"
 #include "SMESH_Mesh.hxx"
 #include "SMESH_MesherHelper.hxx"
 #include "SMESH_subMesh.hxx"
@@ -56,6 +55,7 @@
 #include <TopTools_Array1OfShape.hxx>
 #include <TopTools_DataMapIteratorOfDataMapOfShapeListOfShape.hxx>
 #include <TopTools_DataMapIteratorOfDataMapOfShapeShape.hxx>
+#include <TopTools_IndexedMapOfShape.hxx>
 #include <TopTools_ListIteratorOfListOfShape.hxx>
 #include <TopTools_ListOfShape.hxx>
 #include <TopTools_MapOfShape.hxx>
@@ -307,11 +307,7 @@ namespace {
     if ( gr1It.Value().ShapeType() == TopAbs_FACE )
     {
       // find a boundary edge of group1 to start from
-      TopoDS_Shape bndEdge;
-      TopExp_Explorer edgeExp1( theGroup1, TopAbs_EDGE );
-      for ( ; bndEdge.IsNull() && edgeExp1.More(); edgeExp1.Next())
-        if ( HERE::IsBoundaryEdge( TopoDS::Edge( edgeExp1.Current()), theGroup1, theMesh ))
-          bndEdge = edgeExp1.Current();
+      TopoDS_Shape bndEdge = StdMeshers_ProjectionUtils::GetBoundaryEdge( theGroup1, theMesh );
       if ( bndEdge.IsNull() )
         return false;
 
@@ -375,11 +371,53 @@ namespace {
     return dist2d < tol2d;
   }
 
+  //================================================================================
+  /*!
+   * \brief Returns an EDGE suitable for search of initial vertex association
+   */
+  //================================================================================
+
+  TopoDS_Shape getOuterEdge( const TopoDS_Shape theShape1, SMESH_Mesh& mesh )
+  {
+    TopoDS_Shape edge;
+    if ( theShape1.ShapeType() == TopAbs_COMPOUND )
+    {
+      TopoDS_Iterator it( theShape1 );
+      if ( it.Value().ShapeType() == TopAbs_FACE ) // group of FACEs
+      {
+        // look for a boundary EDGE of a group
+        edge = StdMeshers_ProjectionUtils::GetBoundaryEdge( theShape1, mesh );
+        if ( !edge.IsNull() )
+          return edge;
+      }
+    }
+    edge = theShape1;
+    TopExp_Explorer expF( theShape1, TopAbs_FACE ), expE;
+    if ( expF.More() ) {
+      for ( ; expF.More(); expF.Next() ) {
+        edge.Nullify();
+        TopoDS_Shape wire =
+          StdMeshers_ProjectionUtils::OuterShape( TopoDS::Face( expF.Current() ), TopAbs_WIRE );
+        for ( expE.Init( wire, TopAbs_EDGE ); edge.IsNull() && expE.More(); expE.Next() )
+          if ( !SMESH_MesherHelper::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 ( !SMESH_MesherHelper::IsClosedEdge( TopoDS::Edge( expE.Current() )))
+          edge = expE.Current();
+    }
+    return edge;
+  }
+
 } // namespace
 
 //=======================================================================
 /*!
- * \brief Looks for association of all subshapes of two shapes
+ * \brief Looks for association of all sub-shapes of two shapes
  * \param theShape1 - shape 1
  * \param theMesh1 - mesh built on shape 1
  * \param theShape2 - shape 2
@@ -448,7 +486,7 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the
 
   if ( partner ) // Same shape with different location
   {
-    // recursively associate all subshapes of theShape1 and theShape2
+    // 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();
@@ -556,7 +594,7 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the
       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();
@@ -619,7 +657,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 ));
@@ -936,7 +974,8 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the
         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
@@ -978,13 +1017,14 @@ 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");
-        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();
@@ -1010,15 +1050,8 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the
       if ( AssocGroupsByPropagation( theShape1, theShape2, *theMesh1, theMap ))
         return true;
 
-      // find a boundary edge for theShape1
-      TopoDS_Edge E;
-      for(TopExp_Explorer exp(theShape1, TopAbs_EDGE); exp.More(); exp.Next() ) {
-        E = TopoDS::Edge( exp.Current() );
-        if ( IsBoundaryEdge( E, theShape1, *theMesh1 ))
-          break;
-        else
-          E.Nullify();
-      }
+      // find a boundary edge of theShape1
+      TopoDS_Edge E = GetBoundaryEdge( theShape1, *theMesh1 );
       if ( E.IsNull() )
         break; // try by vertex closeness
 
@@ -1076,12 +1109,13 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the
   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");
@@ -1095,6 +1129,32 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the
     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, bidirect );
+        InsertAssociation( VV1[1], VV1[1], theMap, bidirect );
+        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];
@@ -1116,26 +1176,8 @@ 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();
-  }
+  TopoDS_Shape edge = getOuterEdge( theShape1, *theMesh1 );
   if ( edge.IsNull() || edge.ShapeType() != TopAbs_EDGE )
     RETURN_BAD_RESULT("Edge not found");
 
@@ -1274,9 +1316,10 @@ int StdMeshers_ProjectionUtils::FindFaceAssociation(const TopoDS_Face&    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 ( Abs( v01f1Vec.X()-v01f2Vec.X()) < vTolUV &&
+         Abs( v01f1Vec.Y()-v01f2Vec.Y()) < vTolUV )
     {
-      if ( i_ok_wire_algo != 1 )
+      if ( !OK /*i_ok_wire_algo != 1*/ )
       {
         edges1.clear();
         edges2.clear();
@@ -1477,7 +1520,7 @@ StdMeshers_ProjectionUtils::GetPropagationEdge( SMESH_Mesh*        aMesh,
                                                 const TopoDS_Edge& theEdge,
                                                 const TopoDS_Edge& fromEdge)
 {
-  SMESH_IndexedMapOfShape aChain;
+  TopTools_IndexedMapOfShape aChain;
   int step = 0;
 
   // List of edges, added to chain on the previous cycle pass
@@ -1553,7 +1596,7 @@ StdMeshers_ProjectionUtils::GetPropagationEdge( SMESH_Mesh*        aMesh,
     * \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 assocMap - map associating sub-shapes of the faces
     * \param node1To2Map - map containing found matching nodes
     * \retval bool - is a success
    */
@@ -1609,7 +1652,7 @@ FindMatchingNodesOnFaces( const TopoDS_Face&     face1,
     TopoDS_Edge e1 = TopoDS::Edge( assocMap( e2 ));
     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 );
@@ -1665,7 +1708,7 @@ FindMatchingNodesOnFaces( const TopoDS_Face&     face1,
   if ( hasNodesOnEdge )
   {
     int nbNodeToGet = 1;
-    if ( IsClosedEdge( edge1 ) || IsClosedEdge( edge2 ) )
+    if ( helper1.IsClosedEdge( edge1 ) || helper2.IsClosedEdge( edge2 ) )
       nbNodeToGet = 2;
     for ( int is2 = 0; is2 < 2; ++is2 )
     {
@@ -1753,7 +1796,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;
         }
       }
@@ -1821,7 +1864,7 @@ FindMatchingNodesOnFaces( const TopoDS_Face&     face1,
       while ( nIt->more() ) {
         const SMDS_MeshNode* node = nIt->next();
         const SMDS_EdgePosition* pos =
-          static_cast<const SMDS_EdgePosition*>(node->GetPosition().get());
+          static_cast<const SMDS_EdgePosition*>(node->GetPosition());
         pos2nodes.insert( make_pair( pos->GetUParameter(), node ));
       }
       if ( pos2nodes.size() != edgeSM->NbNodes() )
@@ -1873,25 +1916,12 @@ FindMatchingNodesOnFaces( const TopoDS_Face&     face1,
   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
- */
-//================================================================================
-
-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
+   * \brief Return any sub-shape 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
+    * \param type - type of sub-shape to return
+    * \retval TopoDS_Shape - the found sub-shape
    */
 //================================================================================
 
@@ -1924,7 +1954,7 @@ bool StdMeshers_ProjectionUtils::MakeComputed(SMESH_subMesh * sm, const int iter
 
   SMESH_Mesh* mesh = sm->GetFather();
   SMESH_Gen* gen   = mesh->GetGen();
-  SMESH_Algo* algo = gen->GetAlgo( *mesh, sm->GetSubShape() );
+  SMESH_Algo* algo = sm->GetAlgo();
   if ( !algo )
   {
     if ( sm->GetSubShape().ShapeType() != TopAbs_COMPOUND )
@@ -1988,9 +2018,9 @@ bool StdMeshers_ProjectionUtils::MakeComputed(SMESH_subMesh * sm, const int iter
 
 //================================================================================
 /*!
- * \brief Count nb of subshapes
+ * \brief Count nb of sub-shapes
  * \param shape - the shape
- * \param type - the type of subshapes to count
+ * \param type - the type of sub-shapes to count
  * \retval int - the calculated number
  */
 //================================================================================
@@ -2014,33 +2044,35 @@ int StdMeshers_ProjectionUtils::Count(const TopoDS_Shape&    shape,
 
 //================================================================================
 /*!
- * \brief Return true if edge is a boundary of edgeContainer
+ * \brief Return a boundary EDGE of edgeContainer
  */
 //================================================================================
 
-bool StdMeshers_ProjectionUtils::IsBoundaryEdge(const TopoDS_Edge&  edge,
-                                                const TopoDS_Shape& edgeContainer,
-                                                SMESH_Mesh&         mesh)
+TopoDS_Edge StdMeshers_ProjectionUtils::GetBoundaryEdge(const TopoDS_Shape& edgeContainer,
+                                                        const SMESH_Mesh&   mesh)
 {
   TopTools_IndexedMapOfShape facesOfEdgeContainer, facesNearEdge;
   TopExp::MapShapes( edgeContainer, TopAbs_FACE, facesOfEdgeContainer );
 
-  const TopTools_ListOfShape& EAncestors = mesh.GetAncestors(edge);
-  TopTools_ListIteratorOfListOfShape itea(EAncestors);
-  for(; itea.More(); itea.Next()) {
-    if( itea.Value().ShapeType() == TopAbs_FACE &&
-        facesOfEdgeContainer.Contains( itea.Value() ))
+  if ( !facesOfEdgeContainer.IsEmpty() ) 
+    for ( TopExp_Explorer exp(edgeContainer, TopAbs_EDGE); exp.More(); exp.Next() )
     {
-      facesNearEdge.Add( itea.Value() );
-      if ( facesNearEdge.Extent() > 1 )
-        return false;
+      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 )
+        return edge;
     }
-  }
-  return ( facesNearEdge.Extent() == 1 );
+
+  return TopoDS_Edge();
 }
 
 
-namespace {
+namespace { // Definition of event listeners
 
   SMESH_subMeshEventListener* GetSrcSubMeshListener();
 
@@ -2053,8 +2085,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*)
     {
@@ -2064,9 +2096,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 );
       }
     }
@@ -2088,7 +2118,8 @@ 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;
   }
 }
@@ -2122,7 +2153,7 @@ 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())
         {