Salome HOME
Fix CRASH after mesh.RemoveGroupWithContents( group_of_other_mesh )
[modules/smesh.git] / src / SMDS / SMDS_ElementFactory.cxx
1 // Copyright (C) 2007-2019  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 ( 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<int>& theVtkIDsNewToOld )
285 {
286   int  newNbCells = NbUsedElements();
287   int   maxCellID = GetMaxID();
288   int 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     int 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     int newVtkID = 0; // same as new smds ID (-1)
307     for ( int 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<int>& 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   int  oldNbNodes = myMesh->GetGrid()->GetNumberOfPoints();
387   int  newNbNodes = NbUsedElements();
388   int newNbChunks = newNbNodes / theChunkSize + bool ( newNbNodes % theChunkSize );
389   int   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         int   iChunk = newID / theChunkSize;
414         myChunks[ iChunk ].SetShapeID( newNode, shapeID );
415         if ( shapeDim == 2 || shapeDim == 1 )
416         {
417           int 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 ( int 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, int 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 int 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 int 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 ((int) myFactory->myVtkIDs.size() <= e->GetID() - 1 )
622     {
623       size_t i = myFactory->myVtkIDs.size();
624       myFactory->myVtkIDs.resize( e->GetID() + 100 );
625       for ( ; i < myFactory->myVtkIDs.size(); ++i )
626         myFactory->myVtkIDs[i] = i;
627     }
628     myFactory->myVtkIDs[ e->GetID() - 1 ] = vtkID;
629
630     if ((vtkIdType) myFactory->mySmdsIDs.size() <= vtkID )
631     {
632       size_t i = myFactory->mySmdsIDs.size();
633       myFactory->mySmdsIDs.resize( vtkID + 100 );
634       for ( ; i < myFactory->mySmdsIDs.size(); ++i )
635         myFactory->mySmdsIDs[i] = i;
636     }
637     myFactory->mySmdsIDs[ vtkID ] = e->GetID() - 1;
638   }
639 }
640
641 //================================================================================
642 /*!
643  * \brief Return a Vtk ID of an element
644  */
645 //================================================================================
646
647 int SMDS_ElementChunk::GetVtkID( const SMDS_MeshElement* e ) const
648 {
649   size_t dfltVtkID = e->GetID() - 1;
650   return ( dfltVtkID < myFactory->myVtkIDs.size() ) ? myFactory->myVtkIDs[ dfltVtkID ] : dfltVtkID;
651 }
652
653 //================================================================================
654 /*!
655  * \brief Return ID of a shape an element is assigned to
656  */
657 //================================================================================
658
659 int SMDS_ElementChunk::GetShapeID( const SMDS_MeshElement* e ) const
660 {
661   return mySubIDRanges.GetValue( Index( e ));
662 }
663
664 //================================================================================
665 /*!
666  * \brief Set ID of a shape an element is assigned to
667  */
668 //================================================================================
669
670 void SMDS_ElementChunk::SetShapeID( const SMDS_MeshElement* e, int shapeID ) const
671 {
672   //const size_t nbRanges = mySubIDRanges.Size();
673
674   SMDS_ElementChunk* me = const_cast<SMDS_ElementChunk*>( this );
675   int oldShapeID = me->mySubIDRanges.SetValue( Index( e ), shapeID );
676   if ( oldShapeID == shapeID ) return;
677
678   if ( const SMDS_MeshNode* n = dynamic_cast< const SMDS_MeshNode* >( e ))
679     if ( TParam* uv = me->GetPositionPtr( n ))
680     {
681       uv[0] = 0.;
682       uv[1] = 0.;
683     }
684   // update min/max
685   // if (( nbRanges > mySubIDRanges.Size() ) &&
686   //     ( myMinSubID == oldShapeID || myMaxSubID == oldShapeID ))
687   // {
688   //   me->myMinSubID = ( std::numeric_limits<int>::max() );
689   //   me->myMaxSubID = 0;
690   //   TSubIDRangeSet::set_iterator it;
691   //   for ( it = mySubIDRanges.mySet.begin(); it < mySubIDRanges.mySet.end(); ++it )
692   //     if ( it->myValue > 0 )
693   //     {
694   //       me->myMinSubID = std::min( myMinSubID, it->myValue );
695   //       me->myMaxSubID = std::max( myMaxSubID, it->myValue );
696   //     }
697   // }
698   // else if ( shapeID > 0 )
699   // {
700   //   me->myMinSubID = std::min( myMinSubID, shapeID );
701   //   me->myMaxSubID = std::max( myMaxSubID, shapeID );
702   // }
703 }
704
705 //================================================================================
706 /*!
707  * \brief Set isMarked flag of an element
708  */
709 //================================================================================
710
711 bool SMDS_ElementChunk::IsMarked( const SMDS_MeshElement* e ) const
712 {
713   return ( !myMarkedSet.empty() && myMarkedSet[ Index( e )]);
714 }
715
716 //================================================================================
717 /*!
718  * \brief Return isMarked flag of an element
719  */
720 //================================================================================
721
722 void SMDS_ElementChunk::SetIsMarked( const SMDS_MeshElement* e, bool is )
723 {
724   if ( !is && myMarkedSet.empty() ) return;
725   if ( myMarkedSet.empty() ) myMarkedSet.resize( theChunkSize, false );
726   myMarkedSet[ Index( e )] = is;
727 }
728
729 //================================================================================
730 /*!
731  * \brief Return SMDS_Position of a node on a shape
732  */
733 //================================================================================
734
735 SMDS_PositionPtr SMDS_ElementChunk::GetPosition( const SMDS_MeshNode* n ) const
736 {
737   int  shapeID = GetShapeID( n );
738   int shapeDim = static_cast< SMDS_NodeFactory* >( myFactory )->GetShapeDim( shapeID );
739
740   SMDS_ElementChunk* me = const_cast< SMDS_ElementChunk* >( this );
741
742   switch ( shapeDim ) {
743   case 2:
744   {
745     return SMDS_PositionPtr( new _FacePosition( me->GetPositionPtr( n )));
746   }
747   case 1:
748   {
749     return SMDS_PositionPtr( new _EdgePosition( me->GetPositionPtr( n )));
750   }
751   case 0:
752     return SMDS_VertexPosition::StaticPosition();
753   }
754
755   return SMDS_SpacePosition::originSpacePosition();
756 }
757
758 //================================================================================
759 /*!
760  * \brief Set SMDS_Position of a node on a shape
761  */
762 //================================================================================
763
764 void SMDS_ElementChunk::SetPosition( const SMDS_MeshNode* n, const SMDS_PositionPtr& pos, int shapeID )
765 {
766   int shapeDim = pos ? pos->GetDim() : theDefaultShapeDim;
767   if ( shapeID < 1 )
768   {
769     if ( shapeDim == theDefaultShapeDim )
770       return;
771     shapeID = GetShapeID( n );
772     if ( shapeID < 1 )
773       throw SALOME_Exception("SetPosition() No shape ID provided");
774   }
775
776   static_cast< SMDS_NodeFactory* >( myFactory )->SetShapeDim( shapeID, shapeDim );
777
778   switch ( shapeDim ) {
779   case 2:
780   {
781     TParam* uv = GetPositionPtr( n, /*allocate=*/true );
782     uv[0] = (TParam) pos->GetParameters()[0];
783     uv[1] = (TParam) pos->GetParameters()[1];
784     break;
785   }
786   case 1:
787   {
788     GetPositionPtr( n, /*allocate=*/true )[0] = (TParam) pos->GetParameters()[0];
789     break;
790   }
791   }
792 }
793
794 //================================================================================
795 /*!
796  * \brief Return pointer to on-shape-parameters of a node
797  */
798 //================================================================================
799
800 TParam* SMDS_ElementChunk::GetPositionPtr( const SMDS_MeshElement* n, bool allocate )
801 {
802   if ( myPositions.empty() && !allocate )
803     return 0;
804
805   myPositions.resize( theChunkSize * 2 );
806   return myPositions.data() + 2 * Index( n );
807 }
808
809 //================================================================================
810 /*!
811  * \brief Minimize allocated memory
812  */
813 //================================================================================
814
815 void SMDS_ElementChunk::Compact()
816 {
817   mySubIDRanges.mySet.shrink_to_fit();
818   if ( myUsedRanges.mySet.capacity() > 2 )
819     myUsedRanges.mySet.shrink_to_fit();
820
821   clearVector( myMarkedSet );
822
823   if ( !myPositions.empty() )
824   {
825     // look for the last position that must be kept
826     TSubIDRangeSet::set_t::reverse_iterator it;
827     for ( it = mySubIDRanges.mySet.rbegin(); it != mySubIDRanges.mySet.rend(); ++it )
828     {
829       int shapeDim = static_cast< SMDS_NodeFactory* >( myFactory )->GetShapeDim( it->myValue );
830       if ( shapeDim == 1 || shapeDim == 2 )
831         break;
832     }
833     if ( it == mySubIDRanges.mySet.rend() )
834     {
835       clearVector( myPositions );
836     }
837     else if ( it != mySubIDRanges.mySet.rbegin() )
838     {
839       int nbNodes = (it-1)->my1st;
840       myPositions.resize( nbNodes * 2 );
841       std::vector<TParam> newPos( myPositions.begin(), myPositions.end() );
842       myPositions.swap( newPos );
843     }
844   }
845 }
846
847 //================================================================================
848 /*!
849  * \brief Print some data for debug purposes
850  */
851 //================================================================================
852
853 void SMDS_ElementChunk::Dump() const
854 {
855   std::cout << "1stID: " << my1stID << std::endl;
856
857   //std::cout << "SubID min/max: " << myMinSubID << ", " << myMaxSubID << std::endl;
858   std::cout << "SubIDRanges: " << mySubIDRanges.Size() << " ";
859   {
860     TSubIDRangeSet::set_iterator i = mySubIDRanges.mySet.begin();
861     for ( int cnt = 0; i != mySubIDRanges.mySet.end(); ++i, ++cnt )
862       std::cout << "|" << cnt << " - (" << i->my1st << ", " << i->myValue << ") ";
863     std::cout << std::endl;
864   }
865   {
866     std::cout << "UsedRanges: " << myUsedRanges.Size() << " ";
867     TUsedRangeSet::set_iterator i = myUsedRanges.mySet.begin();
868     for ( int cnt = 0; i != myUsedRanges.mySet.end(); ++i, ++cnt )
869       std::cout << cnt << " - (" << i->my1st << ", " << i->myValue << ") ";
870     std::cout << std::endl;
871   }
872 }
873
874 //================================================================================
875 /*!
876  * \brief Compare SMDS_ElementChunk's
877  */
878 //================================================================================
879
880 bool _ChunkCompare::operator () (const SMDS_ElementChunk* e1, const SMDS_ElementChunk* e2) const
881 {
882   return e1->Get1stID() < e2->Get1stID();
883 }
884