]> SALOME platform Git repositories - modules/smesh.git/blob - src/SMDS/SMDS_ElementFactory.cxx
Salome HOME
Numerate elements starting from MAX_INT
[modules/smesh.git] / src / SMDS / SMDS_ElementFactory.cxx
1 // Copyright (C) 2007-2020  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22 //  File   : SMDS_ElementFactory.cxx
23 //  Module : SMESH
24 //
25
26 #include "SMDS_ElementFactory.hxx"
27
28 #include "ObjectPool.hxx"
29 #include "SMDS_EdgePosition.hxx"
30 #include "SMDS_FacePosition.hxx"
31 #include "SMDS_Mesh.hxx"
32 #include "SMDS_SpacePosition.hxx"
33 #include "SMDS_VertexPosition.hxx"
34
35 namespace
36 {
37   // nb of elements allocated by SMDS_ElementChunk at once
38   const int theChunkSize = 1024;
39
40   const int theDefaultShapeDim = 3;
41
42   const smIdType idShift = 2147483647;
43
44   // classes allowing to modify parameters of SMDS_Position stored in SMDS_ElementFactory
45
46   struct _EdgePosition : public SMDS_EdgePosition
47   {
48     TParam* myUParameter;
49
50     _EdgePosition( TParam* aUParam ) : myUParameter( aUParam )
51     { SMDS_EdgePosition::SetUParameter( aUParam[0]); }
52     virtual void   SetUParameter(double aUparam)
53     { *myUParameter = (TParam) aUparam; SMDS_EdgePosition::SetUParameter( aUparam ); }
54   };
55
56   struct _FacePosition : public SMDS_FacePosition
57   {
58     TParam* myParameter;
59
60     _FacePosition(TParam* aParam) : myParameter( aParam )
61     { SMDS_FacePosition::SetParameters( aParam[0], aParam[1] ); }
62     virtual void SetUParameter(double aUparam)
63     { myParameter[0] = (TParam) aUparam; SMDS_FacePosition::SetUParameter( aUparam ); }
64     virtual void SetVParameter(double aVparam)
65     { myParameter[1] = (TParam) aVparam; SMDS_FacePosition::SetVParameter( aVparam ); }
66     virtual void SetParameters(double aU, double aV)
67     { myParameter[0] = aU; myParameter[1] = aV; SMDS_FacePosition::SetParameters( aU, aV ); }
68   };
69 }
70
71 //================================================================================
72 /*!
73  * \brief Create a factory of cells or nodes in a given mesh
74  */
75 //================================================================================
76
77 SMDS_ElementFactory::SMDS_ElementFactory( SMDS_Mesh* mesh, const bool isNodal )
78   : myIsNodal( isNodal ), myMesh( mesh ), myNbUsedElements( 0 )
79 {
80 }
81
82 //================================================================================
83 /*!
84  * \brief Destructor
85  */
86 //================================================================================
87
88 SMDS_ElementFactory::~SMDS_ElementFactory()
89 {
90   myChunksWithUnused.clear();
91   myChunks.clear();
92 }
93
94 //================================================================================
95 /*!
96  * \brief Return a number of elements in a chunk
97  *  \return int - chunk size
98  */
99 //================================================================================
100
101 int SMDS_ElementFactory::ChunkSize()
102 {
103   return theChunkSize;
104 }
105
106 //================================================================================
107 /*!
108  * \brief Return minimal ID of a non-used element
109  *  \return smIdType - minimal element ID
110  */
111 //================================================================================
112
113 smIdType SMDS_ElementFactory::GetFreeID()
114 {
115   if ( myChunksWithUnused.empty() )
116   {
117     smIdType id0 = myChunks.size() * theChunkSize + 1;
118     id0 += idShift;
119     myChunks.push_back( new SMDS_ElementChunk( this, id0 ));
120   }
121   SMDS_ElementChunk * chunk = (*myChunksWithUnused.begin());
122   return chunk->GetUnusedID();
123 }
124
125 //================================================================================
126 /*!
127  * \brief Return maximal ID of an used element
128  *  \return smIdType - element ID
129  */
130 //================================================================================
131
132 smIdType SMDS_ElementFactory::GetMaxID()
133 {
134   smIdType id = 0;
135   TIndexRanges usedRanges;
136   for ( smIdType i = myChunks.size() - 1; i >= 0; --i )
137     if ( myChunks[i].GetUsedRanges().GetIndices( true, usedRanges ))
138     {
139       int index = usedRanges.back().second-1;
140       id = myChunks[i].Get1stID() + index;
141       break;
142     }
143   return id;
144 }
145
146 //================================================================================
147 /*!
148  * \brief Return minimal ID of an used element
149  *  \return smIdType - element ID
150  */
151 //================================================================================
152
153 smIdType SMDS_ElementFactory::GetMinID()
154 {
155   smIdType id = 0;
156   TIndexRanges usedRanges;
157   for ( size_t i = 0; i < myChunks.size(); ++i )
158     if ( myChunks[i].GetUsedRanges().GetIndices( true, usedRanges ))
159     {
160       int index = usedRanges[0].first;
161       id = myChunks[i].Get1stID() + index;
162       break;
163     }
164   return id;
165 }
166
167 //================================================================================
168 /*!
169  * \brief Return an element by ID. NULL if the element with the given ID is already used
170  *  \param [in] id - element ID
171  *  \return SMDS_MeshElement* - element pointer
172  */
173 //================================================================================
174
175 SMDS_MeshElement* SMDS_ElementFactory::NewElement( const smIdType ID )
176 {
177   smIdType id = ID - idShift;
178   smIdType iChunk = ( id - 1 ) / theChunkSize;
179   smIdType index  = ( id - 1 ) % theChunkSize;
180   while ((smIdType) myChunks.size() <= iChunk )
181   {
182     smIdType id0 = myChunks.size() * theChunkSize + 1;
183     myChunks.push_back( new SMDS_ElementChunk( this, id0 ));
184   }
185   SMDS_MeshElement* e = myChunks[iChunk].Element( FromIdType<int>(index) );
186   if ( !e->IsNull() )
187     return 0; // element with given ID already exists
188
189   myChunks[iChunk].UseElement( FromIdType<int>(index) );
190   ++myNbUsedElements;
191
192   e->myHolder = & myChunks[iChunk];
193
194   myMesh->setMyModified();
195
196   return e;
197 }
198
199 //================================================================================
200 /*!
201  * \brief Return an used element by ID. NULL if the element with the given ID is not yet used
202  *  \param [in] id - element ID
203  *  \return const SMDS_MeshElement* - element pointer
204  */
205 //================================================================================
206
207 const SMDS_MeshElement* SMDS_ElementFactory::FindElement( const smIdType ID ) const
208 {
209   smIdType id = ID -idShift;
210   if ( id > 0 )
211   {
212     smIdType iChunk = ( id - 1 ) / theChunkSize;
213     smIdType index  = ( id - 1 ) % theChunkSize;
214     if ( iChunk < (smIdType) myChunks.size() )
215     {
216       const SMDS_MeshElement* e = myChunks[iChunk].Element( FromIdType<int>(index) );
217       return e->IsNull() ? 0 : e;
218     }
219   }
220   return 0;
221 }
222
223 //================================================================================
224 /*!
225  * \brief Return an SMDS ID by a Vtk one
226  *  \param [inout] vtkID - Vtk ID
227  *  \return smIdType - SMDS ID
228  */
229 //================================================================================
230
231 smIdType SMDS_ElementFactory::FromVtkToSmds( vtkIdType VTKID )
232 {
233   vtkIdType vtkID = VTKID - idShift;
234   if ( vtkID >= 0 && vtkID < (vtkIdType)mySmdsIDs.size() )
235     return mySmdsIDs[vtkID] + 1;
236   return vtkID + 1 + idShift;
237 }
238
239 //================================================================================
240 /*!
241  * \brief Mark the element as non-used
242  *  \param [in] e - element
243  */
244 //================================================================================
245
246 void SMDS_ElementFactory::Free( const SMDS_MeshElement* e )
247 {
248   if ( e != FindElement( e->GetID() ))
249     SALOME_Exception("SMDS_ElementFactory::Free(): element of other mesh");
250
251   if ( !myVtkIDs.empty() )
252   {
253     size_t    id = e->GetID() - 1 - idShift;
254     size_t vtkID = e->GetVtkID() - idShift;
255     if ( id < myVtkIDs.size() )
256       myVtkIDs[ id ] = -1;
257     if ( vtkID < mySmdsIDs.size() )
258       mySmdsIDs[ vtkID ] = -1;
259   }
260   e->myHolder->Free( e );
261   const_cast< SMDS_MeshElement*>( e )->myHolder = 0;
262   --myNbUsedElements;
263
264   myMesh->setMyModified();
265 }
266
267 //================================================================================
268 /*!
269  * \brief De-allocate all elements
270  */
271 //================================================================================
272
273 void SMDS_ElementFactory::Clear()
274 {
275   myChunksWithUnused.clear();
276   clearVector( myChunks );
277   clearVector( myVtkIDs );
278   clearVector( mySmdsIDs );
279   myNbUsedElements = 0;
280 }
281
282 //================================================================================
283 /*!
284  * \brief Remove unused elements located not at the end of the last chunk.
285  *        Minimize allocated memory
286  *  \param [out] theVtkIDsNewToOld - theVtkIDsNewToOld[ new VtkID ] = old VtkID
287  */
288 //================================================================================
289
290 void SMDS_ElementFactory::Compact( std::vector<smIdType>& theVtkIDsNewToOld )
291 {
292   smIdType  newNbCells = NbUsedElements();
293   smIdType   maxCellID = GetMaxID();
294   smIdType newNbChunks = newNbCells / theChunkSize + bool ( newNbCells % theChunkSize );
295
296   theVtkIDsNewToOld.resize( newNbCells );
297
298   if ( newNbCells == 0 ) // empty mesh
299   {
300     clearVector( myChunks );
301   }
302   else if ( newNbCells == maxCellID ) // no holes
303   {
304     smIdType newID, minLastID = std::min( myVtkIDs.size(), theVtkIDsNewToOld.size() );
305     for ( newID = 0; newID < minLastID; ++newID )
306       theVtkIDsNewToOld[ newID ] = myVtkIDs[ newID ];
307     for ( ; newID < newNbCells; ++newID )
308       theVtkIDsNewToOld[ newID ] = newID;
309   }
310   else // there are holes in SMDS IDs
311   {
312     smIdType newVtkID = 0; // same as new smds ID (-1)
313     for ( smIdType oldID = 1; oldID <= maxCellID; ++oldID ) // smds IDs
314     {
315       const SMDS_MeshElement* oldElem = FindElement( oldID );
316       if ( !oldElem ) continue;
317       theVtkIDsNewToOld[ newVtkID++ ] = oldElem->GetVtkID(); // now newVtkID == new smds ID
318       if ( oldID != newVtkID )
319       {
320         const SMDS_MeshElement* newElem = FindElement( newVtkID );
321         if ( !newElem )
322           newElem = NewElement( newVtkID );
323         if ( int shapeID = oldElem->GetShapeID() )
324           const_cast< SMDS_MeshElement* >( newElem )->setShapeID( shapeID );
325         if ( oldID > newNbCells )
326           Free( oldElem );
327       }
328     }
329   }
330   myChunks.resize( newNbChunks );
331
332   myChunksWithUnused.clear();
333   if ( !myChunks.empty() && myChunks.back().GetUsedRanges().Size() > 1 )
334     myChunksWithUnused.insert( & myChunks.back() );
335
336   for ( size_t i = 0; i < myChunks.size(); ++i )
337     myChunks[i].Compact();
338
339   clearVector( myVtkIDs );
340   clearVector( mySmdsIDs );
341 }
342
343
344 //================================================================================
345 /*!
346  * \brief Return true if Compact() will change IDs of elements
347  */
348 //================================================================================
349
350 bool SMDS_ElementFactory::CompactChangePointers()
351 {
352   // there can be VTK_EMPTY_CELL's in the VTK grid as well as "holes" in SMDS numeration
353   return ( NbUsedElements() != GetMaxID() );
354 }
355
356 //================================================================================
357 /*!
358  * \brief Create a factory of nodes in a given mesh
359  */
360 //================================================================================
361
362 SMDS_NodeFactory::SMDS_NodeFactory( SMDS_Mesh* mesh )
363   : SMDS_ElementFactory( mesh, /*isNodal=*/true )
364 {
365 }
366
367 //================================================================================
368 /*!
369  * \brief Destructor
370  */
371 //================================================================================
372
373 SMDS_NodeFactory::~SMDS_NodeFactory()
374 {
375   Clear();
376 }
377
378 //================================================================================
379 /*!
380  * \brief Remove unused nodes located not at the end of the last chunk.
381  *        Minimize allocated memory
382  *  \param [out] theVtkIDsOldToNew - vector storing change of vtk IDs
383  */
384 //================================================================================
385
386 void SMDS_NodeFactory::Compact( std::vector<smIdType>& theVtkIDsOldToNew )
387 {
388   // IDs of VTK nodes always correspond to SMDS IDs but there can be "holes"
389   // in the chunks. So we remove holes and report relocation in theVtkIDsOldToNew:
390   // theVtkIDsOldToNew[ old VtkID ] = new VtkID
391
392   smIdType  oldNbNodes = myMesh->GetGrid()->GetNumberOfPoints();
393   smIdType  newNbNodes = NbUsedElements();
394   smIdType newNbChunks = newNbNodes / theChunkSize + bool ( newNbNodes % theChunkSize );
395   smIdType   maxNodeID = GetMaxID();
396
397   theVtkIDsOldToNew.resize( oldNbNodes, -1 );
398
399   if ( newNbNodes == 0 ) // empty mesh
400   {
401     clearVector( myChunks );
402   }
403   else if ( maxNodeID > newNbNodes ) // there are holes
404   {
405     size_t newID = 0;
406     for ( size_t oldID = 0; oldID < theVtkIDsOldToNew.size(); ++oldID )
407     {
408       const SMDS_MeshElement* oldNode = FindNode( oldID+1 );
409       if ( !oldNode )
410         continue;
411       theVtkIDsOldToNew[ oldID ] = newID;
412       if ( oldID != newID )
413       {
414         const SMDS_MeshElement* newNode = FindElement( newID+1 );
415         if ( !newNode )
416           newNode = NewElement( newID+1 );
417         int     shapeID = oldNode->GetShapeID();
418         int    shapeDim = GetShapeDim( shapeID );
419         smIdType iChunk = newID / theChunkSize;
420         myChunks[ iChunk ].SetShapeID( newNode, shapeID );
421         if ( shapeDim == 2 || shapeDim == 1 )
422         {
423           smIdType iChunkOld = oldID / theChunkSize;
424           TParam* oldPos = myChunks[ iChunkOld ].GetPositionPtr( oldNode );
425           TParam* newPos = myChunks[ iChunk    ].GetPositionPtr( newNode, /*allocate=*/true );
426           if ( oldPos )
427           {
428             newPos[0] = oldPos[0];
429             newPos[1] = oldPos[1];
430           }
431         }
432         if ( oldNode->GetID() > newNbNodes )
433           Free( oldNode );
434       }
435       ++newID;
436     }
437   }
438   else // no holes
439   {
440     for ( smIdType i = 0; i < newNbNodes; ++i )
441       theVtkIDsOldToNew[ i ] = i;
442   }
443   myChunks.resize( newNbChunks );
444
445   myChunksWithUnused.clear();
446   if ( !myChunks.empty() && myChunks.back().GetUsedRanges().Size() > 1 )
447     myChunksWithUnused.insert( & myChunks.back() );
448
449   for ( size_t i = 0; i < myChunks.size(); ++i )
450     myChunks[i].Compact();
451
452   ASSERT( newNbNodes == GetMaxID() );
453   ASSERT( newNbNodes == NbUsedElements() );
454 }
455
456 //================================================================================
457 /*!
458  * \brief Return true if Compact() will change IDs of elements
459  */
460 //================================================================================
461
462 bool SMDS_NodeFactory::CompactChangePointers()
463 {
464   // IDs of VTK nodes always correspond to SMDS IDs but there can be "holes" in SMDS numeration
465   return ( NbUsedElements() != GetMaxID() );
466 }
467
468 //================================================================================
469 /*!
470  * \brief De-allocate all nodes
471  */
472 //================================================================================
473
474 void SMDS_NodeFactory::Clear()
475 {
476   SMDS_ElementFactory::Clear();
477 }
478
479 //================================================================================
480 /*!
481  * \brief Set a total number of sub-shapes in the main shape
482  */
483 //================================================================================
484
485 void SMDS_NodeFactory::SetNbShapes( size_t nbShapes )
486 {
487   clearVector( myShapeDim );
488   myShapeDim.resize( nbShapes+1, theDefaultShapeDim );
489 }
490
491 //================================================================================
492 /*!
493  * \brief Return a dimension of a shape
494  */
495 //================================================================================
496
497 int SMDS_NodeFactory::GetShapeDim( int shapeID ) const
498 {
499   return shapeID < (int)myShapeDim.size() ? myShapeDim[ shapeID ] : theDefaultShapeDim;
500 }
501
502 //================================================================================
503 /*!
504  * \brief Set a dimension of a shape
505  */
506 //================================================================================
507
508 void SMDS_NodeFactory::SetShapeDim( int shapeID, int dim )
509 {
510   if ( shapeID >= (int)myShapeDim.size() )
511     myShapeDim.resize( shapeID + 10, theDefaultShapeDim );
512   myShapeDim[ shapeID ] = dim;
513 }
514
515 //================================================================================
516 /*!
517  * \brief SMDS_ElementChunk constructor
518  *  \param [in] factory - the factory
519  *  \param [in] id0 - ID of the 1st element
520  */
521 //================================================================================
522
523 SMDS_ElementChunk::SMDS_ElementChunk( SMDS_ElementFactory* factory, smIdType id0 ):
524   myFactory( factory ),
525   my1stID( id0 )//,
526   //mySubIDSet( 0 )
527   // myMinSubID( std::numeric_limits<int>::max() ),
528   // myMaxSubID( 0 )
529 {
530   if ( !myFactory )
531     return;
532   if ( myFactory->myIsNodal )
533     myElements = new SMDS_MeshNode[ theChunkSize ];
534   else
535     myElements = new SMDS_MeshCell[ theChunkSize ];
536
537   myUsedRanges.mySet.reserve(2);
538   mySubIDRanges.mySet.insert( _ShapeIDRange( 0, 0 ));
539   myUsedRanges.mySet.insert( _UsedRange( 0, false ));
540   myFactory->myChunksWithUnused.insert( this );
541 }
542
543 //================================================================================
544 /*!
545  * \brief SMDS_ElementChunk destructor
546  */
547 //================================================================================
548
549 SMDS_ElementChunk::~SMDS_ElementChunk()
550 {
551   delete [] myElements;
552   myFactory->myChunksWithUnused.erase( this );
553 }
554
555 //================================================================================
556 /*!
557  * \brief Mark an element as used
558  */
559 //================================================================================
560
561 void SMDS_ElementChunk::UseElement( const int index )
562 {
563   myUsedRanges.SetValue( index, true );
564   if ( myUsedRanges.Size() == 1 ) // all elements used
565     myFactory->myChunksWithUnused.erase( this );
566 }
567
568 //================================================================================
569 /*!
570  * \brief Return ID of the first non-used element
571  */
572 //================================================================================
573
574 smIdType SMDS_ElementChunk::GetUnusedID() const
575 {
576   TUsedRangeSet::set_iterator r = myUsedRanges.mySet.begin();
577   for ( ; r != myUsedRanges.mySet.end(); ++r )
578     if ( !IsUsed( *r ))
579       break;
580
581   return my1stID + r->my1st;
582 }
583
584 //================================================================================
585 /*!
586  * \brief Mark an element as non-used
587  */
588 //================================================================================
589
590 void SMDS_ElementChunk::Free( const SMDS_MeshElement* e )
591 {
592   bool hasHoles = ( myUsedRanges.Size() > 1 );
593   myUsedRanges.SetValue( Index( e ), false );
594   SetShapeID( e, 0 ); // sub-mesh must do it?
595   SetIsMarked( e, false );
596   if ( !hasHoles )
597     myFactory->myChunksWithUnused.insert( this );
598
599   if ( myUsedRanges.Size() == 1 )
600   {
601     clearVector( myMarkedSet );
602     clearVector( myPositions );
603   }
604 }
605
606 //================================================================================
607 /*!
608  * \brief Return an SMDS ID of an element
609  */
610 //================================================================================
611
612 smIdType SMDS_ElementChunk::GetID( const SMDS_MeshElement* e ) const
613 {
614   return my1stID + Index( e );
615 }
616
617 //================================================================================
618 /*!
619  * \brief Set a Vtk ID of an element
620  */
621 //================================================================================
622
623 void SMDS_ElementChunk::SetVTKID( const SMDS_MeshElement* e, const vtkIdType vtkID )
624 {
625   smIdType id = e->GetID() - idShift;
626   if ( id - 1 != vtkID )
627   {
628     if ((smIdType) myFactory->myVtkIDs.size() <= id - 1 )
629     {
630       vtkIdType i = (vtkIdType) myFactory->myVtkIDs.size();
631       myFactory->myVtkIDs.resize( id + 100 );
632       vtkIdType newSize = (vtkIdType) myFactory->myVtkIDs.size();
633       for ( ; i < newSize; ++i )
634         myFactory->myVtkIDs[i] = i;
635     }
636     myFactory->myVtkIDs[ id - 1 ] = vtkID;
637
638     if ((vtkIdType) myFactory->mySmdsIDs.size() <= vtkID )
639     {
640       size_t i = myFactory->mySmdsIDs.size();
641       myFactory->mySmdsIDs.resize( vtkID + 100 );
642       for ( ; i < myFactory->mySmdsIDs.size(); ++i )
643         myFactory->mySmdsIDs[i] = i;
644     }
645     myFactory->mySmdsIDs[ vtkID ] = e->GetID() - 1;
646   }
647 }
648
649 //================================================================================
650 /*!
651  * \brief Return a Vtk ID of an element
652  */
653 //================================================================================
654
655 vtkIdType SMDS_ElementChunk::GetVtkID( const SMDS_MeshElement* e ) const
656 {
657   vtkIdType dfltVtkID = FromIdType<vtkIdType>(e->GetID() - 1) - idShift;
658   return ( dfltVtkID < (vtkIdType)myFactory->myVtkIDs.size() ) ? myFactory->myVtkIDs[ dfltVtkID ] : dfltVtkID;
659 }
660
661 //================================================================================
662 /*!
663  * \brief Return ID of a shape an element is assigned to
664  */
665 //================================================================================
666
667 int SMDS_ElementChunk::GetShapeID( const SMDS_MeshElement* e ) const
668 {
669   return mySubIDRanges.GetValue( Index( e ));
670 }
671
672 //================================================================================
673 /*!
674  * \brief Set ID of a shape an element is assigned to
675  */
676 //================================================================================
677
678 void SMDS_ElementChunk::SetShapeID( const SMDS_MeshElement* e, int shapeID ) const
679 {
680   //const size_t nbRanges = mySubIDRanges.Size();
681
682   SMDS_ElementChunk* me = const_cast<SMDS_ElementChunk*>( this );
683   int oldShapeID = me->mySubIDRanges.SetValue( Index( e ), shapeID );
684   if ( oldShapeID == shapeID ) return;
685
686   if ( const SMDS_MeshNode* n = dynamic_cast< const SMDS_MeshNode* >( e ))
687     if ( TParam* uv = me->GetPositionPtr( n ))
688     {
689       uv[0] = 0.;
690       uv[1] = 0.;
691     }
692   // update min/max
693   // if (( nbRanges > mySubIDRanges.Size() ) &&
694   //     ( myMinSubID == oldShapeID || myMaxSubID == oldShapeID ))
695   // {
696   //   me->myMinSubID = ( std::numeric_limits<int>::max() );
697   //   me->myMaxSubID = 0;
698   //   TSubIDRangeSet::set_iterator it;
699   //   for ( it = mySubIDRanges.mySet.begin(); it < mySubIDRanges.mySet.end(); ++it )
700   //     if ( it->myValue > 0 )
701   //     {
702   //       me->myMinSubID = std::min( myMinSubID, it->myValue );
703   //       me->myMaxSubID = std::max( myMaxSubID, it->myValue );
704   //     }
705   // }
706   // else if ( shapeID > 0 )
707   // {
708   //   me->myMinSubID = std::min( myMinSubID, shapeID );
709   //   me->myMaxSubID = std::max( myMaxSubID, shapeID );
710   // }
711 }
712
713 //================================================================================
714 /*!
715  * \brief Set isMarked flag of an element
716  */
717 //================================================================================
718
719 bool SMDS_ElementChunk::IsMarked( const SMDS_MeshElement* e ) const
720 {
721   return ( !myMarkedSet.empty() && myMarkedSet[ Index( e )]);
722 }
723
724 //================================================================================
725 /*!
726  * \brief Return isMarked flag of an element
727  */
728 //================================================================================
729
730 void SMDS_ElementChunk::SetIsMarked( const SMDS_MeshElement* e, bool is )
731 {
732   if ( !is && myMarkedSet.empty() ) return;
733   if ( myMarkedSet.empty() ) myMarkedSet.resize( theChunkSize, false );
734   myMarkedSet[ Index( e )] = is;
735 }
736
737 //================================================================================
738 /*!
739  * \brief Return SMDS_Position of a node on a shape
740  */
741 //================================================================================
742
743 SMDS_PositionPtr SMDS_ElementChunk::GetPosition( const SMDS_MeshNode* n ) const
744 {
745   int  shapeID = GetShapeID( n );
746   int shapeDim = static_cast< SMDS_NodeFactory* >( myFactory )->GetShapeDim( shapeID );
747
748   SMDS_ElementChunk* me = const_cast< SMDS_ElementChunk* >( this );
749
750   switch ( shapeDim ) {
751   case 2:
752   {
753     return SMDS_PositionPtr( new _FacePosition( me->GetPositionPtr( n )));
754   }
755   case 1:
756   {
757     return SMDS_PositionPtr( new _EdgePosition( me->GetPositionPtr( n )));
758   }
759   case 0:
760     return SMDS_VertexPosition::StaticPosition();
761   }
762
763   return SMDS_SpacePosition::originSpacePosition();
764 }
765
766 //================================================================================
767 /*!
768  * \brief Set SMDS_Position of a node on a shape
769  */
770 //================================================================================
771
772 void SMDS_ElementChunk::SetPosition( const SMDS_MeshNode* n, const SMDS_PositionPtr& pos, int shapeID )
773 {
774   int shapeDim = pos ? pos->GetDim() : theDefaultShapeDim;
775   if ( shapeID < 1 )
776   {
777     if ( shapeDim == theDefaultShapeDim )
778       return;
779     shapeID = GetShapeID( n );
780     if ( shapeID < 1 )
781       throw SALOME_Exception("SetPosition() No shape ID provided");
782   }
783
784   static_cast< SMDS_NodeFactory* >( myFactory )->SetShapeDim( shapeID, shapeDim );
785
786   switch ( shapeDim ) {
787   case 2:
788   {
789     TParam* uv = GetPositionPtr( n, /*allocate=*/true );
790     uv[0] = (TParam) pos->GetParameters()[0];
791     uv[1] = (TParam) pos->GetParameters()[1];
792     break;
793   }
794   case 1:
795   {
796     GetPositionPtr( n, /*allocate=*/true )[0] = (TParam) pos->GetParameters()[0];
797     break;
798   }
799   }
800 }
801
802 //================================================================================
803 /*!
804  * \brief Return pointer to on-shape-parameters of a node
805  */
806 //================================================================================
807
808 TParam* SMDS_ElementChunk::GetPositionPtr( const SMDS_MeshElement* n, bool allocate )
809 {
810   if ( myPositions.empty() && !allocate )
811     return 0;
812
813   myPositions.resize( theChunkSize * 2 );
814   return myPositions.data() + 2 * Index( n );
815 }
816
817 //================================================================================
818 /*!
819  * \brief Minimize allocated memory
820  */
821 //================================================================================
822
823 void SMDS_ElementChunk::Compact()
824 {
825   mySubIDRanges.mySet.shrink_to_fit();
826   if ( myUsedRanges.mySet.capacity() > 2 )
827     myUsedRanges.mySet.shrink_to_fit();
828
829   clearVector( myMarkedSet );
830
831   if ( !myPositions.empty() )
832   {
833     // look for the last position that must be kept
834     TSubIDRangeSet::set_t::reverse_iterator it;
835     for ( it = mySubIDRanges.mySet.rbegin(); it != mySubIDRanges.mySet.rend(); ++it )
836     {
837       int shapeDim = static_cast< SMDS_NodeFactory* >( myFactory )->GetShapeDim( it->myValue );
838       if ( shapeDim == 1 || shapeDim == 2 )
839         break;
840     }
841     if ( it == mySubIDRanges.mySet.rend() )
842     {
843       clearVector( myPositions );
844     }
845     else if ( it != mySubIDRanges.mySet.rbegin() )
846     {
847       int nbNodes = (it-1)->my1st;
848       myPositions.resize( nbNodes * 2 );
849       std::vector<TParam> newPos( myPositions.begin(), myPositions.end() );
850       myPositions.swap( newPos );
851     }
852   }
853 }
854
855 //================================================================================
856 /*!
857  * \brief Print some data for debug purposes
858  */
859 //================================================================================
860
861 void SMDS_ElementChunk::Dump() const
862 {
863   std::cout << "1stID: " << my1stID << std::endl;
864
865   //std::cout << "SubID min/max: " << myMinSubID << ", " << myMaxSubID << std::endl;
866   std::cout << "SubIDRanges: " << mySubIDRanges.Size() << " ";
867   {
868     TSubIDRangeSet::set_iterator i = mySubIDRanges.mySet.begin();
869     for ( int cnt = 0; i != mySubIDRanges.mySet.end(); ++i, ++cnt )
870       std::cout << "|" << cnt << " - (" << i->my1st << ", " << i->myValue << ") ";
871     std::cout << std::endl;
872   }
873   {
874     std::cout << "UsedRanges: " << myUsedRanges.Size() << " ";
875     TUsedRangeSet::set_iterator i = myUsedRanges.mySet.begin();
876     for ( int cnt = 0; i != myUsedRanges.mySet.end(); ++i, ++cnt )
877       std::cout << cnt << " - (" << i->my1st << ", " << i->myValue << ") ";
878     std::cout << std::endl;
879   }
880 }
881
882 //================================================================================
883 /*!
884  * \brief Compare SMDS_ElementChunk's
885  */
886 //================================================================================
887
888 bool _ChunkCompare::operator () (const SMDS_ElementChunk* e1, const SMDS_ElementChunk* e2) const
889 {
890   return e1->Get1stID() < e2->Get1stID();
891 }
892