Salome HOME
Regression of SALOME_TESTS/Grids/smesh/3D_mesh_Extrusion_01/B8
authoreap <eap@opencascade.com>
Wed, 8 Aug 2018 13:55:53 +0000 (16:55 +0300)
committereap <eap@opencascade.com>
Wed, 8 Aug 2018 13:55:53 +0000 (16:55 +0300)
 Optimize iteration on sub-mesh elements

+ minor doc fix

13 files changed:
doc/salome/gui/SMESH/input/basic_meshing_algos.rst
doc/salome/gui/SMESH/input/cartesian_algo.rst
doc/salome/gui/SMESH/input/mesh_preferences.rst
doc/salome/gui/SMESH/input/modifying_meshes.rst
src/SMDS/SMDS_CellOfNodes.hxx
src/SMDS/SMDS_ElementFactory.cxx
src/SMDS/SMDS_ElementFactory.hxx
src/SMDS/SMDS_ElementHolder.cxx
src/SMDS/SMDS_Mesh.cxx
src/SMDS/SMDS_Mesh.hxx
src/SMESHDS/SMESHDS_SubMesh.cxx
src/SMESHDS/SMESHDS_SubMesh.hxx
src/SMESH_SWIG/smeshBuilder.py

index 9033c31..692232f 100644 (file)
@@ -6,7 +6,7 @@ Basic meshing algorithms
 
 The MESH module contains a set of meshing algorithms, which are        used for meshing entities (1D, 2D, 3D sub-shapes) composing geometrical objects.
 
-.. note:: Algorithms added to the module as plug-ins are described in documentation of the plug-ins.
+.. note:: Algorithms added to the module as plug-ins are described in documentation of the plug-ins (menu **Help / User's Guide / Mesh module / Plugins**).
 
 An algorithm represents either an implementation of a certain meshing technique or an interface to the whole meshing program generating elements of several dimensions.
 
index bde18de..46605bb 100644 (file)
@@ -15,6 +15,8 @@ boundary.
 .. centered::
        A sphere meshed by Body Fitting algorithm
 
+.. note:: The algorithm creates only 3D elements. To add 2D elements use :ref:`Generate boundary elements <make_2dmesh_from_3d_page>` operation.
+
 The meshing algorithm is as follows.
 
 #. Lines of a Cartesian structured grid defined by :ref:`Body Fitting Parameters <cartesian_hyp_anchor>` hypothesis are intersected with the geometry boundary, thus nodes lying on the boundary are found. This step also allows finding out for each node of the Cartesian grid if it is inside or outside the geometry. 
index ccf0f76..d804e4c 100644 (file)
@@ -117,8 +117,9 @@ General Preferences
 * **Python Dump**
 
   * **Historical python dump** - allows switching between *Historical* and *Snapshot* dump mode:
-  * In *Historical* mode, Python Dump script includes all commands performed by SMESH engine.
-  * In *Snapshot* mode, the commands relating to objects removed from the Study as well as the commands not influencing the current state of meshes are excluded from the script.
+
+    * In *Historical* mode, Python Dump script includes all commands performed by SMESH engine.
+    * In *Snapshot* mode, the commands relating to objects removed from the Study as well as the commands not influencing the current state of meshes are excluded from the script.
 
 .. _mesh_tab_preferences:
 
index 62c4149..3c9b7d1 100644 (file)
@@ -8,37 +8,37 @@ Salome provides a vast specter of mesh modification and transformation operation
 
 * :ref:`Add <adding_nodes_and_elements_page>` mesh elements from nodes to polyhedrons at an arbitrary place in the mesh.
 * :ref:`Add quadratic <adding_quadratic_elements_page>` mesh elements from quadratic segments to quadratic hexahedrons at an arbitrary place in the mesh.
-* :ref:`Remove <removing_nodes_and_elements_page>` any existin" mesh elements and nodes.
+* :ref:`Remove <removing_nodes_and_elements_page>` any existing mesh elements and nodes.
+* :ref:`Convert linear mesh to quadratic <convert_to_from_quadratic_mesh_page>`, or vice versa.
+* :ref:`Generate boundary elements <make_2dmesh_from_3d_page>`.
 * :ref:`Translate <translation_page>` in the indicated direction the mesh or some of its elements.
 * :ref:`Rotate <rotation_page>` by the indicated axis and angle the mesh or some of its elements.
 * :ref:`Scale <scale_page>` the mesh or some of its elements.
 * :ref:`Mirror <symmetry_page>` the mesh through a point, a vector or a plane of symmetry.
 * :ref:`double_nodes_page`. Duplication of nodes can be useful to emulate a crack in the model.
-* Unite meshes by :ref:`sewing <sewing_meshes_page>` free borders, border to side or side elements.
 * :ref:`Merge Nodes<merging_nodes_page>` coincident within the indicated tolerance.
 * :ref:`Merge Elements <merging_elements_page>` based on the same nodes.
+* Create an :ref:`extrusion <extrusion_page>` along a vector or by normal to a discretized surface.
+* Create an :ref:`extrusion along a path <extrusion_along_path_page>`.
+* Create elements by :ref:`revolution <revolution_page>` of the selected nodes and elements.
 * :ref:`Move Nodes <mesh_through_point_page>` to an arbitrary location with consequent transformation of all adjacent elements.
+* :ref:`Change orientation <changing_orientation_of_elements_page>` of the selected elements.
+* :ref:`Orient faces <reorient_faces_page>` by several means.
+* Unite meshes by :ref:`sewing <sewing_meshes_page>` free borders, border to side or side elements.
 * :ref:`Invert an edge <diagonal_inversion_of_elements_page>` between neighboring triangles.
 * :ref:`Unite two triangles <uniting_two_triangles_page>`.
 * :ref:`Unite several adjacent triangles <uniting_set_of_triangles_page>`.
-* :ref:`Change orientation <changing_orientation_of_elements_page>` of the selected elements.
-* :ref:`Orient faces <reorient_faces_page>` by several means.
 * :ref:`Cut a quadrangle <cutting_quadrangles_page>` into two triangles.
 * :ref:`Split <split_to_tetra_page>` volumic elements into tetrahedra or prisms.
 * :ref:`Split bi-quadratic <split_biquad_to_linear_page>` elements into linear ones without creation of additional nodes.
 * :ref:`Smooth <smoothing_page>` elements, reducung distortions in them by adjusting the locations of nodes.
-* Create an :ref:`extrusion <extrusion_page>` along a vector or by normal to a discretized surface.
-* Create an :ref:`extrusion along a path <extrusion_along_path_page>`.
-* Create elements by :ref:`revolution <revolution_page>` of the selected nodes and elements.
 * Apply :ref:`pattern mapping <pattern_mapping_page>`.
-* :ref:`Convert linear mesh to quadratic <convert_to_from_quadratic_mesh_page>`, or vice versa.
-* :ref:`Generate boundary elements <make_2dmesh_from_3d_page>`.
 * :ref:`generate_flat_elements_page`.
 * :ref:`cut_mesh_by_plane_page`.
 
 
 .. note::
-       It is possible to :ref:`modify the mesh <edit_anchor>` of a lower dimension before generation of the mesh of a higher dimension.
+       You can use these operations to :ref:`modify the mesh <edit_anchor>` of a lower dimension before generation of the mesh of a higher dimension.
 
 .. note::
        It is possible to use the variables defined in the SALOME **NoteBook** to specify the numerical parameters used for modification of any object.
index 4880d07..b20b7cf 100644 (file)
@@ -33,7 +33,7 @@
 
 // ============================================================
 /*!
- * \brief Base class for elements of not contained in the mesh
+ * \brief Base class for elements not contained in the mesh
  */
 // ============================================================
 
index a6d61e8..48d25af 100644 (file)
@@ -513,9 +513,10 @@ void SMDS_NodeFactory::SetShapeDim( int shapeID, int dim )
 
 SMDS_ElementChunk::SMDS_ElementChunk( SMDS_ElementFactory* factory, int id0 ):
   myFactory( factory ),
-  my1stID( id0 ),
-  myMinSubID( std::numeric_limits<int>::max() ),
-  myMaxSubID( 0 )
+  my1stID( id0 )//,
+  //mySubIDSet( 0 )
+  // myMinSubID( std::numeric_limits<int>::max() ),
+  // myMaxSubID( 0 )
 {
   if ( !myFactory )
     return;
@@ -665,7 +666,7 @@ int SMDS_ElementChunk::GetShapeID( const SMDS_MeshElement* e ) const
 
 void SMDS_ElementChunk::SetShapeID( const SMDS_MeshElement* e, int shapeID ) const
 {
-  const size_t nbRanges = mySubIDRanges.Size();
+  //const size_t nbRanges = mySubIDRanges.Size();
 
   SMDS_ElementChunk* me = const_cast<SMDS_ElementChunk*>( this );
   int oldShapeID = me->mySubIDRanges.SetValue( Index( e ), shapeID );
@@ -678,24 +679,24 @@ void SMDS_ElementChunk::SetShapeID( const SMDS_MeshElement* e, int shapeID ) con
       uv[1] = 0.;
     }
   // update min/max
-  if (( nbRanges > mySubIDRanges.Size() ) &&
-      ( myMinSubID == oldShapeID || myMaxSubID == oldShapeID ))
-  {
-    me->myMinSubID = ( std::numeric_limits<int>::max() );
-    me->myMaxSubID = 0;
-    TSubIDRangeSet::set_iterator it;
-    for ( it = mySubIDRanges.mySet.begin(); it < mySubIDRanges.mySet.end(); ++it )
-      if ( it->myValue > 0 )
-      {
-        me->myMinSubID = std::min( myMinSubID, it->myValue );
-        me->myMaxSubID = std::max( myMaxSubID, it->myValue );
-      }
-  }
-  else if ( shapeID > 0 )
-  {
-    me->myMinSubID = std::min( myMinSubID, shapeID );
-    me->myMaxSubID = std::max( myMaxSubID, shapeID );
-  }
+  // if (( nbRanges > mySubIDRanges.Size() ) &&
+  //     ( myMinSubID == oldShapeID || myMaxSubID == oldShapeID ))
+  // {
+  //   me->myMinSubID = ( std::numeric_limits<int>::max() );
+  //   me->myMaxSubID = 0;
+  //   TSubIDRangeSet::set_iterator it;
+  //   for ( it = mySubIDRanges.mySet.begin(); it < mySubIDRanges.mySet.end(); ++it )
+  //     if ( it->myValue > 0 )
+  //     {
+  //       me->myMinSubID = std::min( myMinSubID, it->myValue );
+  //       me->myMaxSubID = std::max( myMaxSubID, it->myValue );
+  //     }
+  // }
+  // else if ( shapeID > 0 )
+  // {
+  //   me->myMinSubID = std::min( myMinSubID, shapeID );
+  //   me->myMaxSubID = std::max( myMaxSubID, shapeID );
+  // }
 }
 
 //================================================================================
@@ -850,7 +851,7 @@ void SMDS_ElementChunk::Dump() const
 {
   std::cout << "1stID: " << my1stID << std::endl;
 
-  std::cout << "SubID min/max: " << myMinSubID << ", " << myMaxSubID << std::endl;
+  //std::cout << "SubID min/max: " << myMinSubID << ", " << myMaxSubID << std::endl;
   std::cout << "SubIDRanges: " << mySubIDRanges.Size() << " ";
   {
     TSubIDRangeSet::set_iterator i = mySubIDRanges.mySet.begin();
index 18c3d94..5fb6b3b 100644 (file)
@@ -108,8 +108,12 @@ public:
   //! Return an iterator on all element assigned to a given shape.
   //  nbElemsToReturn is used to optimize by stopping the iteration as soon as
   //  all elements assigned to the shape encountered.
+  //  sm1stElem is used to quickly find the first chunk holding elements of the shape;
+  //  it must have smallest ID between elements on the shape
   template< class ElemIterator >
-  boost::shared_ptr< ElemIterator > GetShapeIterator( int shapeID, size_t nbElemsToReturn );
+  boost::shared_ptr< ElemIterator > GetShapeIterator( int                     shapeID,
+                                                      size_t                  nbElemsToReturn,
+                                                      const SMDS_MeshElement* sm1stElem );
 
   //! Mark the element as non-used
   void Free( const SMDS_MeshElement* );
@@ -231,9 +235,9 @@ struct _RangeSet
   {
     bool isFound = false;
 
-    if ( sizeof( attr_t ) == sizeof( int ) && theMinValue )
-      if ( theValue < *theMinValue || theValue > *theMaxValue )
-        return isFound;
+    // if ( sizeof( attr_t ) == sizeof( int ) && theMinValue )
+    //   if ( theValue < *theMinValue || theValue > *theMaxValue )
+    //     return isFound;
 
     for ( set_iterator it = mySet.begin(); it < mySet.end(); ++it )
     {
@@ -354,6 +358,7 @@ typedef _RangeSet< _UsedRange >    TUsedRangeSet;
 typedef boost::dynamic_bitset<>    TBitSet;
 //typedef float                       TParam;
 typedef double                     TParam;
+//typedef std::unordered_set<int>    TSubIDSet;
 
 //------------------------------------------------------------------------------------
 /*!
@@ -369,8 +374,9 @@ class SMDS_ElementChunk
   TBitSet              myMarkedSet;   // mark some elements
   TUsedRangeSet        myUsedRanges;  // ranges of used/unused elements
   TSubIDRangeSet       mySubIDRanges; // ranges of elements on the same sub-shape
-  int                  myMinSubID;    // min sub-shape ID
-  int                  myMaxSubID;    // max sub-shape ID
+  //TSubIDSet*           mySubIDSet;    // set of sub-shape IDs
+  // int                  myMinSubID;    // min sub-shape ID
+  // int                  myMaxSubID;    // max sub-shape ID
   std::vector<TParam>  myPositions;   // UV parameters on shape: 2*param_t per an element
 
 public:
@@ -412,7 +418,7 @@ public:
 
   //! Return ranges of elements assigned to sub-shapes and min/max of sub-shape IDs
   const TSubIDRangeSet& GetSubIDRangesMinMax( int& min, int& max ) const
-  { min = myMinSubID; max = myMaxSubID; return mySubIDRanges; }
+  { /*min = myMinSubID; max = myMaxSubID;*/ return mySubIDRanges; }
 
   //! Minimize allocated memory
   void Compact();
@@ -469,11 +475,12 @@ struct _ChunkIterator : public ELEM_ITERATOR
                   get_rangeset_fun          theGetRangeSetFun,
                   attr_type                 theAttrValue,
                   SMDS_MeshElement::Filter* theFilter,
-                  size_t                    theNbElemsToReturn = -1):
+                  size_t                    theNbElemsToReturn = -1,
+                  int                       theChunkIndex = 0):
     myElement( 0 ),
     myRangeIndex( 0 ),
     myChunks( theChunks ),
-    myChunkIndex( -1 ),
+    myChunkIndex( theChunkIndex-1 ),
     myGetRangeSetFun( theGetRangeSetFun ),
     myValue( theAttrValue ),
     myFilter( theFilter ),
@@ -552,14 +559,18 @@ SMDS_ElementFactory::GetIterator( SMDS_MeshElement::Filter* filter,
 
 template< class ElemIterator >
 boost::shared_ptr< ElemIterator >
-SMDS_ElementFactory::GetShapeIterator( int shapeID, size_t nbElemsToReturn )
+SMDS_ElementFactory::GetShapeIterator( int                     shapeID,
+                                       size_t                  nbElemsToReturn,
+                                       const SMDS_MeshElement* sm1stElem )
 {
+  int iChunk = sm1stElem ? (( sm1stElem->GetID() - 1 ) / ChunkSize()) : 0;
   typedef _ChunkIterator< ElemIterator, TSubIDRangeSet > TChuckIterator;
   return boost::make_shared< TChuckIterator >( myChunks,
                                                & SMDS_ElementChunk::GetSubIDRangesMinMax,
                                                /*shapeID=*/shapeID,
                                                new SMDS_MeshElement::NonNullFilter(),
-                                               nbElemsToReturn );
+                                               nbElemsToReturn,
+                                               iChunk );
 }
 
 #endif
index 0913590..fd4dc82 100644 (file)
@@ -37,7 +37,8 @@
 SMDS_ElementHolder::SMDS_ElementHolder( const SMDS_Mesh* mesh )
   : myMesh( const_cast< SMDS_Mesh* >( mesh ))
 {
-  myPtrInMesh = myMesh->myElemHolders.insert( this ).first;
+  if ( myMesh )
+    myPtrInMesh = myMesh->myElemHolders.insert( this ).first;
 }
 
 //=======================================================================
@@ -47,7 +48,8 @@ SMDS_ElementHolder::SMDS_ElementHolder( const SMDS_Mesh* mesh )
 
 SMDS_ElementHolder::~SMDS_ElementHolder()
 {
-  myMesh->myElemHolders.erase( myPtrInMesh );
+  if ( myMesh )
+    myMesh->myElemHolders.erase( myPtrInMesh );
 }
 
 //=======================================================================
index 790ff1b..a117394 100644 (file)
@@ -1611,14 +1611,18 @@ SMDS_VolumeIteratorPtr SMDS_Mesh::volumesIterator() const
                                              myInfo.NbVolumes());
 }
 
-SMDS_NodeIteratorPtr SMDS_Mesh::shapeNodesIterator(int shapeID, size_t nbElemsToReturn) const
+SMDS_NodeIteratorPtr SMDS_Mesh::shapeNodesIterator(int                  shapeID,
+                                                   size_t               nbElemsToReturn,
+                                                   const SMDS_MeshNode* sm1stNode) const
 {
-  return myNodeFactory->GetShapeIterator< SMDS_NodeIterator >( shapeID, nbElemsToReturn );
+  return myNodeFactory->GetShapeIterator< SMDS_NodeIterator >( shapeID, nbElemsToReturn, sm1stNode );
 }
 
-SMDS_ElemIteratorPtr SMDS_Mesh::shapeElementsIterator(int shapeID, size_t nbElemsToReturn) const
+SMDS_ElemIteratorPtr SMDS_Mesh::shapeElementsIterator(int                     shapeID,
+                                                      size_t                  nbElemsToReturn,
+                                                      const SMDS_MeshElement* sm1stElem) const
 {
-  return myCellFactory->GetShapeIterator< SMDS_ElemIterator >( shapeID, nbElemsToReturn );
+  return myCellFactory->GetShapeIterator< SMDS_ElemIterator >( shapeID, nbElemsToReturn, sm1stElem );
 }
 
 ///////////////////////////////////////////////////////////////////////////////
index e81735e..2661253 100644 (file)
@@ -66,8 +66,12 @@ public:
   virtual SMDS_ElemIteratorPtr elementGeomIterator(SMDSAbs_GeometryType type) const;
   virtual SMDS_ElemIteratorPtr elementEntityIterator(SMDSAbs_EntityType type) const;
 
-  virtual SMDS_NodeIteratorPtr shapeNodesIterator   (int shapeID, size_t nbElemsToReturn=-1) const;
-  virtual SMDS_ElemIteratorPtr shapeElementsIterator(int shapeID, size_t nbElemsToReturn=-1) const;
+  virtual SMDS_NodeIteratorPtr shapeNodesIterator   (int                  shapeID,
+                                                     size_t               nbElemsToReturn=-1,
+                                                     const SMDS_MeshNode* sm1stNode=0) const;
+  virtual SMDS_ElemIteratorPtr shapeElementsIterator(int                     shapeID,
+                                                     size_t                  nbElemsToReturn=-1,
+                                                     const SMDS_MeshElement* sm1stElem=0) const;
 
   SMDSAbs_ElementType GetElementType( const int id, const bool iselem ) const;
 
index 4a086e3..26c9ec1 100644 (file)
 //
 #include "SMESHDS_SubMesh.hxx"
 
-#include "SMESHDS_Mesh.hxx"
-#include "SMDS_SetIterator.hxx"
 #include "SMDS_ElementFactory.hxx"
+#include "SMDS_IteratorOnIterators.hxx"
+#include "SMDS_SetIterator.hxx"
+#include "SMESHDS_Mesh.hxx"
 
 #include <utilities.h>
 
+namespace
+{
+  typedef const SMDS_MeshElement* PElem;
+  typedef const SMDS_MeshNode*    PNode;
+
+  typedef SMDS_SetIterator< PElem, PElem const *,
+                            SMDS::SimpleAccessor< PElem, PElem const * >,
+                            SMDS::NonNullFilter< PElem > >                 EArrayIterator;
+
+  typedef SMDS_SetIterator< PNode, PNode const *,
+                            SMDS::SimpleAccessor< PNode, PNode const * >,
+                            SMDS::NonNullFilter< PNode > >                 NArrayIterator;
+
+  int ind1st( SMDSAbs_ElementType t )
+  {
+    return t == SMDSAbs_Node;
+  }
+
+  //=======================================================================
+  //class : _MyElemIteratorFromNodeIterator
+  //=======================================================================
+  class _MyElemIteratorFromNodeIterator : public SMDS_ElemIterator
+  {
+    SMDS_NodeIteratorPtr myItr;
+  public:
+    _MyElemIteratorFromNodeIterator(SMDS_NodeIteratorPtr nodeItr): myItr( nodeItr ) {}
+    bool more()                    { return myItr->more(); }
+    const SMDS_MeshElement* next() { return myItr->next(); }
+  };
+}
+
 //================================================================================
 /*!
  * \brief Constructor
 //================================================================================
 
 SMESHDS_SubMesh::SMESHDS_SubMesh(SMESHDS_Mesh *parent, int index)
+  : SMDS_ElementHolder( parent )
 {
   myParent = parent;
   myIndex = index;
   myNbElements = 0;
   myNbNodes = 0;
+  my1stElemNode[0] = my1stElemNode[1] = 0;
 }
 
 //================================================================================
@@ -84,6 +118,9 @@ void SMESHDS_SubMesh::AddElement(const SMDS_MeshElement * elem)
 
     elem->setShapeID( myIndex );
     myNbElements++;
+
+    // remember element with smallest ID to optimize iteration on them
+    add( elem );
   }
 }
 
@@ -102,6 +139,11 @@ bool SMESHDS_SubMesh::RemoveElement(const SMDS_MeshElement * elem )
   {
     elem->setShapeID( 0 );
     myNbElements--;
+
+    const SMDS_MeshElement* & elem1st = my1stElemNode[ ind1st( elem->GetType() )];
+    if ( elem1st == elem )
+      elem1st = 0;
+
     return true;
   }
   return false;
@@ -126,6 +168,9 @@ void SMESHDS_SubMesh::AddNode(const SMDS_MeshNode * N)
     }
     N->setShapeID( myIndex );
     myNbNodes++;
+
+    // remember node with smallest ID to optimize iteration on them
+    add( N );
   }
 }
 
@@ -144,6 +189,11 @@ bool SMESHDS_SubMesh::RemoveNode(const SMDS_MeshNode * N)
   {
     N->setShapeID( 0 );
     myNbNodes--;
+
+    const SMDS_MeshElement* & node1st = my1stElemNode[ ind1st( SMDSAbs_Node )];
+    if ( node1st == N )
+      node1st = 0;
+
     return true;
   }
   return false;
@@ -185,49 +235,6 @@ int SMESHDS_SubMesh::NbNodes() const
   return nbElems;
 }
 
-/*!
- * Template class used for iteration on vector of elements which can resize
- * during iteration. The iterator returns only elements present upon its creation.
- */
-template <class ELEM, typename TSET> class MySetIterator : public SMDS_Iterator<ELEM>
-{
-protected:
-  int _iCur, _iEnd, _iDelta;
-  const TSET& _table;
-public:
-  MySetIterator(const TSET& table, bool reverse): _table( table )
-  {
-    if ( reverse )
-    {
-      _iCur = _table.size()-1;
-      _iEnd = -1;
-      _iDelta = -1;
-    }
-    else
-    {
-      _iCur = 0;
-      _iEnd = _table.size();
-      _iDelta = 1;
-    }
-    if ( more() && !_table[ _iCur ])
-      next();
-  }
-
-  virtual bool more()
-  {
-    return ( _iEnd - _iCur ) * _iDelta > 0;
-  }
-
-  virtual ELEM next()
-  {
-    ELEM e = more() ? _table[ _iCur ] : 0;
-    _iCur += _iDelta;
-    while ( more() && !_table[ _iCur ])
-      _iCur += _iDelta;
-    return e;
-  }
-};
-
 // =====================
 // class MyIterator
 // =====================
@@ -301,7 +308,13 @@ SMDS_ElemIteratorPtr SMESHDS_SubMesh::GetElements() const
   if ( IsComplexSubmesh() )
     return SMDS_ElemIteratorPtr( new MyElemIterator( mySubMeshes ));
 
-  return myParent->shapeElementsIterator( myIndex, myNbElements );
+  const SMDS_MeshElement* const * elem1st = & my1stElemNode[ ind1st( SMDSAbs_All )];
+  if ( myNbElements == 1 )
+  {
+    return boost::make_shared< EArrayIterator >( elem1st, elem1st+1 );
+  }
+
+  return myParent->shapeElementsIterator( myIndex, myNbElements, *elem1st );
 }
 
 //=======================================================================
@@ -314,7 +327,14 @@ SMDS_NodeIteratorPtr SMESHDS_SubMesh::GetNodes() const
   if ( IsComplexSubmesh() )
     return SMDS_NodeIteratorPtr( new MyNodeIterator( mySubMeshes ));
 
-  return myParent->shapeNodesIterator( myIndex, myNbNodes );
+  PNode const * node1st =
+    reinterpret_cast< PNode const* >( & my1stElemNode[ ind1st( SMDSAbs_Node )] );
+  if ( myNbNodes == 1 )
+  {
+    return boost::make_shared< NArrayIterator >( node1st, node1st+1 );
+  }
+
+  return myParent->shapeNodesIterator( myIndex, myNbNodes, *node1st );
 }
 
 //=======================================================================
@@ -438,6 +458,7 @@ void SMESHDS_SubMesh::Clear()
 
   myNbElements = 0;
   myNbNodes = 0;
+  my1stElemNode[0] = my1stElemNode[1] = 0;
   if ( NbSubMeshes() > 0 )
   {
     SMESHDS_SubMeshIteratorPtr sub = GetSubMeshIterator();
@@ -447,3 +468,43 @@ void SMESHDS_SubMesh::Clear()
     }
   }
 }
+
+//=======================================================================
+//function : getElements
+//purpose  : Return iterator on all elements and nodes during compacting
+//=======================================================================
+
+SMDS_ElemIteratorPtr SMESHDS_SubMesh::getElements()
+{
+  if ( IsComplexSubmesh() ) // return nothing
+    boost::make_shared< EArrayIterator >( & my1stElemNode[0], & my1stElemNode[0] );
+
+  typedef std::vector< SMDS_ElemIteratorPtr > TIterVec;
+  TIterVec iterVec(2);
+  iterVec[0] = GetElements();
+  iterVec[1].reset( new _MyElemIteratorFromNodeIterator( GetNodes() ));
+
+  return boost::make_shared< SMDS_IteratorOnIterators< PElem, TIterVec > >( iterVec );
+}
+
+//=======================================================================
+//function : tmpClear
+//purpose  : clean up after compacting
+//=======================================================================
+
+void SMESHDS_SubMesh::tmpClear()
+{
+  my1stElemNode[0] = my1stElemNode[1] = 0;
+}
+
+//=======================================================================
+//function : add
+//purpose  : update my1stElemNode
+//=======================================================================
+
+void SMESHDS_SubMesh::add( const SMDS_MeshElement* elem )
+{
+  const SMDS_MeshElement* & oldElem = my1stElemNode[ ind1st( elem->GetType() )];
+  if ( !oldElem || oldElem->GetID() > elem->GetID() )
+    oldElem = elem;
+}
index 2caffb1..f25ebfe 100644 (file)
@@ -29,6 +29,7 @@
 
 #include "SMESH_SMESHDS.hxx"
 
+#include "SMDS_ElementHolder.hxx"
 #include "SMDS_Mesh.hxx"
 #include <vector>
 
@@ -42,7 +43,7 @@ typedef boost::shared_ptr< SMESHDS_SubMeshIterator > SMESHDS_SubMeshIteratorPtr;
 
 class SMESHDS_Mesh;
 
-class SMESHDS_EXPORT SMESHDS_SubMesh
+class SMESHDS_EXPORT SMESHDS_SubMesh : public SMDS_ElementHolder
 {
  public:
   SMESHDS_SubMesh(SMESHDS_Mesh *parent, int index);
@@ -55,8 +56,6 @@ class SMESHDS_EXPORT SMESHDS_SubMesh
   virtual bool RemoveElement(const SMDS_MeshElement * ME); // ret true if ME was in
   virtual void AddNode(const SMDS_MeshNode * ME);
   virtual bool RemoveNode(const SMDS_MeshNode * ME);       // ret true if ME was in
-  //virtual const SMDS_MeshElement* GetElement( size_t idInShape ) const;
-  //virtual const SMDS_MeshNode*    GetNode   ( size_t idInShape ) const;
 
   // if IsComplexSubmesh()
   void AddSubMesh( const SMESHDS_SubMesh* theSubMesh );
@@ -80,13 +79,21 @@ class SMESHDS_EXPORT SMESHDS_SubMesh
   SMESHDS_Mesh* GetParent() const { return const_cast< SMESHDS_Mesh*>( myParent ); }
   int           GetID()     const { return myIndex; }
 
+ protected: // methods of SMDS_ElementHolder
+
+  virtual SMDS_ElemIteratorPtr getElements();
+  virtual void tmpClear();
+  virtual void add( const SMDS_MeshElement* element );
+  virtual void compact() {}
+
  private:
 
-  int             myIndex;
-  int             myNbElements;
-  int             myNbNodes;
-  SMESHDS_Mesh *  myParent;
-  TSubMeshSet     mySubMeshes;
+  int                     myIndex;
+  int                     myNbElements;
+  int                     myNbNodes;
+  const SMDS_MeshElement* my1stElemNode[2]; // elem and node with least ID, to optimize iteration
+  SMESHDS_Mesh *          myParent;
+  TSubMeshSet             mySubMeshes;
 
 };
 #endif
index 147d8dd..c21f7f0 100644 (file)
@@ -2189,10 +2189,11 @@ class Mesh(metaclass = MeshMeta):
                 fields: list of GEOM fields defined on the shape to mesh.
                 geomAssocFields: each character of this string means a need to export a 
                         corresponding field; correspondence between fields and characters is following:
-                        - 'v' stands for "_vertices _" field;
-                        - 'e' stands for "_edges _" field;
-                        - 'f' stands for "_faces _" field;
-                        - 's' stands for "_solids _" field.
+
+                        - 'v' stands for "_vertices_" field;
+                        - 'e' stands for "_edges_" field;
+                        - 'f' stands for "_faces_" field;
+                        - 's' stands for "_solids_" field.
         """
         # process positional arguments
         #args = [i for i in args if i not in [SMESH.MED_V2_1, SMESH.MED_V2_2]] # backward compatibility