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