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