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