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