Salome HOME
2cb9aca8af0cf7503afffe743d7dc776c3a1c74a
[modules/smesh.git] / src / SMESHDS / SMESHDS_SubMesh.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
23 //  SMESH SMESHDS : management of mesh data and SMESH document
24 //  File   : SMESH_SubMesh.cxx
25 //  Author : Yves FRICAUD, OCC
26 //  Module : SMESH
27 //  $Header: 
28 //
29 #include "SMESHDS_SubMesh.hxx"
30 #include "SMESHDS_Mesh.hxx"
31
32 #include "utilities.h"
33 #include "SMDS_SetIterator.hxx"
34 #include <iostream>
35 #include <cassert>
36
37 using namespace std;
38
39
40 //================================================================================
41 /*!
42  * \brief Constructor
43  */
44 //================================================================================
45
46 SMESHDS_SubMesh::SMESHDS_SubMesh(SMESHDS_Mesh *parent, int index)
47 {
48   myParent = parent;
49   myIndex = index;
50   myUnusedIdNodes = 0;
51   myUnusedIdElements = 0;
52 }
53
54 //================================================================================
55 /*!
56  * \brief Destructor
57  */
58 //================================================================================
59
60 SMESHDS_SubMesh::~SMESHDS_SubMesh()
61 {
62 }
63
64 //=======================================================================
65 //function : AddElement
66 //purpose  :
67 //=======================================================================
68
69 void SMESHDS_SubMesh::AddElement(const SMDS_MeshElement * ME)
70 {
71   if (!IsComplexSubmesh())
72   {
73     if ( ME->GetType() == SMDSAbs_Node )
74     {
75       AddNode( static_cast< const SMDS_MeshNode* >( ME ));
76       return;
77     }
78     int oldShapeId = ME->getshapeId();
79     if ( oldShapeId > 0 )
80     {
81       if (oldShapeId != myIndex)
82       {
83         throw SALOME_Exception
84           (LOCALIZED("add element in subshape already belonging to a subshape"));
85       }
86       int idInSubShape = ME->getIdInShape();
87       if (idInSubShape >= 0)
88       {
89         MESSAGE("add element in subshape already belonging to that subshape "
90                 << ME->GetID() << " " << oldShapeId << " " << idInSubShape);
91         // check if ok: do nothing if ok
92         if (idInSubShape >= (int)myElements.size())
93         {
94           throw SALOME_Exception(LOCALIZED("out of bounds"));
95         }
96         if (ME != myElements[idInSubShape])
97         {
98           throw SALOME_Exception(LOCALIZED("not the same element"));
99         }
100         return;
101       }
102     }
103
104     SMDS_MeshElement* elem = (SMDS_MeshElement*) (ME);
105     elem->setShapeId(myIndex);
106     elem->setIdInShape(myElements.size());
107     myElements.push_back(ME);
108   }
109 }
110
111 //=======================================================================
112 //function : RemoveElement
113 //purpose  :
114 //=======================================================================
115
116 bool SMESHDS_SubMesh::RemoveElement(const SMDS_MeshElement * ME, bool isElemDeleted)
117 {
118   if (!ME)
119   {
120     return false;
121   }
122   if (!IsComplexSubmesh())
123   {
124     if ( ME->getshapeId() != myIndex ) // elem not in a pool can loose it's data already
125     {
126       if ( isElemDeleted )
127         for ( size_t i = 0; i < myElements.size(); ++i )
128           if ( myElements[i] == ME )
129           {
130             myElements[i] = 0;
131             ++myUnusedIdElements;
132             return true;
133           }
134       return false;
135     }
136     int idInSubShape = ME->getIdInShape();
137     SMDS_MeshElement* elem = (SMDS_MeshElement*) (ME);
138     elem->setShapeId(0);
139     elem->setIdInShape(-1);
140     if ((idInSubShape >= 0) && (idInSubShape < (int) myElements.size()))
141     {
142       myElements[idInSubShape] = 0; // this vector entry is no more used
143       if ( ++myUnusedIdElements == (int) myElements.size() )
144       {
145         clearVector( myElements );
146         myUnusedIdElements = 0;
147       }
148       return true;
149     }
150     return false;
151   }
152   return false;
153 }
154
155 //=======================================================================
156 //function : AddNode
157 //purpose  :
158 //=======================================================================
159
160 void SMESHDS_SubMesh::AddNode(const SMDS_MeshNode * N)
161 {
162   if ( !IsComplexSubmesh() )
163   {
164     const int idInSubShape = N->getIdInShape();
165     const int shapeId      = N->getshapeId();
166     if ((shapeId > 0) && (idInSubShape >= 0))
167     {
168       if ( shapeId != myIndex )
169         throw SALOME_Exception
170           (LOCALIZED("a node being in sub-mesh is added to another sub-mesh"));
171       if ( idInSubShape >= (int)myNodes.size() || myNodes[ idInSubShape ] != N )
172         throw SALOME_Exception
173           (LOCALIZED("a node with wrong idInSubShape is re-added to the same sub-mesh"));
174       return; // already in
175     }
176     SMDS_MeshNode* node = (SMDS_MeshNode*)(N);
177     node->setShapeId(myIndex);
178     node->setIdInShape(myNodes.size());
179     myNodes.push_back(N);
180   }
181 }
182
183 //=======================================================================
184 //function : RemoveNode
185 //purpose  :
186 //=======================================================================
187
188 bool SMESHDS_SubMesh::RemoveNode(const SMDS_MeshNode * N, bool isNodeDeleted)
189 {
190   if (!IsComplexSubmesh())
191   {
192     if ( N->getshapeId() != myIndex )
193     {
194       if ( isNodeDeleted )
195         for ( size_t i = 0; i < myNodes.size(); ++i )
196           if ( myNodes[i] == N )
197           {
198             myNodes[i] = 0;
199             ++myUnusedIdNodes;
200             return true;
201           }
202       return false;
203     }
204     int idInSubShape = N->getIdInShape();
205     SMDS_MeshNode* node = (SMDS_MeshNode*) (N);
206     node->setShapeId(0);
207     node->setIdInShape(-1);
208     if ((idInSubShape >= 0) && (idInSubShape < (int) myNodes.size()))
209     {
210       myNodes[idInSubShape] = 0; // this vector entry is no more used
211       if ( ++myUnusedIdNodes == (int) myNodes.size() )
212       {
213         clearVector( myNodes );
214         myUnusedIdNodes = 0;
215       }
216       return true;
217     }
218     return false;
219   }
220   return false;
221 }
222
223 //=======================================================================
224 //function : NbElements
225 //purpose  :
226 //=======================================================================
227
228 int SMESHDS_SubMesh::NbElements() const
229 {
230   if ( !IsComplexSubmesh() )
231     return myElements.size() - myUnusedIdElements;
232
233   int nbElems = 0;
234   set<const SMESHDS_SubMesh*>::const_iterator it = mySubMeshes.begin();
235   for ( ; it != mySubMeshes.end(); it++ )
236     nbElems += (*it)->NbElements();
237
238   return nbElems;
239 }
240
241 //=======================================================================
242 //function : NbNodes
243 //purpose  :
244 //=======================================================================
245
246 int SMESHDS_SubMesh::NbNodes() const
247 {
248   if ( !IsComplexSubmesh() )
249     return myNodes.size() - myUnusedIdNodes;
250
251   int nbElems = 0;
252   set<const SMESHDS_SubMesh*>::const_iterator it = mySubMeshes.begin();
253   for ( ; it != mySubMeshes.end(); it++ )
254     nbElems += (*it)->NbNodes();
255
256   return nbElems;
257 }
258
259 /*!
260  * template class used for iteration on submesh elements. Interface of iterator remains
261  * unchanged after redesign of SMDS to avoid modification everywhere in SMESH.
262  * instances are stored in shared_ptr for automatic destruction.
263  * Container is copied for iteration, because original can be modified
264  * by addition of elements, for instance, and then reallocated (vector)
265  */
266 template <class ELEM, typename TSET> class MySetIterator : public SMDS_Iterator<ELEM>
267 {
268 protected:
269   typename TSET::const_iterator _it, _end;
270   TSET _table;
271 public:
272   MySetIterator(const TSET& table)
273   {
274     _table = table;
275     _it = _table.begin();
276     _end = _table.end();
277     while ((_it != _end) && (*_it == 0))
278       _it++;
279   }
280
281   virtual bool more()
282   {
283     while ((_it != _end) && (*_it == 0))
284       _it++;
285     return (_it != _end);
286   }
287
288   virtual ELEM next()
289   {
290     ELEM e = *_it;
291     _it++;
292     return e;
293   }
294 };
295
296 // =====================
297 // class MyIterator
298 // =====================
299
300 template<typename VALUE> class MyIterator : public SMDS_Iterator<VALUE>
301 {
302 public:
303   MyIterator (const set<const SMESHDS_SubMesh*>& theSubMeshes)
304     : myMore(false), mySubIt( theSubMeshes.begin() ), mySubEnd( theSubMeshes.end() )
305   {}
306   bool more()
307   {
308     while (( !myElemIt.get() || !myElemIt->more() ) && mySubIt != mySubEnd)
309     {
310       myElemIt = getElements(*mySubIt);
311       mySubIt++;
312     }
313     myMore = myElemIt.get() && myElemIt->more();
314     return myMore;
315   }
316   VALUE next()
317   {
318     VALUE elem = 0;
319     if ( myMore )
320       elem = myElemIt->next();
321     return elem;
322   }
323 protected:
324   virtual boost::shared_ptr< SMDS_Iterator<VALUE> >
325   getElements(const SMESHDS_SubMesh*) const = 0;
326
327 private:
328   bool                                        myMore;
329   set<const SMESHDS_SubMesh*>::const_iterator mySubIt, mySubEnd;
330   boost::shared_ptr< SMDS_Iterator<VALUE> >   myElemIt;
331 };
332
333 // =====================
334 // class MyElemIterator
335 // =====================
336
337 class MyElemIterator: public MyIterator<const SMDS_MeshElement*>
338 {
339 public:
340   MyElemIterator (const set<const SMESHDS_SubMesh*>& theSubMeshes)
341     :MyIterator<const SMDS_MeshElement*>( theSubMeshes ) {}
342   SMDS_ElemIteratorPtr getElements(const SMESHDS_SubMesh* theSubMesh) const
343   { return theSubMesh->GetElements(); }
344 };
345
346 // =====================
347 // class MyNodeIterator
348 // =====================
349
350 class MyNodeIterator: public MyIterator<const SMDS_MeshNode*>
351 {
352 public:
353   MyNodeIterator (const set<const SMESHDS_SubMesh*>& theSubMeshes)
354     :MyIterator<const SMDS_MeshNode*>( theSubMeshes ) {}
355   SMDS_NodeIteratorPtr getElements(const SMESHDS_SubMesh* theSubMesh) const
356   { return theSubMesh->GetNodes(); }
357 };
358
359 //=======================================================================
360 //function : GetElements
361 //purpose  :
362 //=======================================================================
363
364 SMDS_ElemIteratorPtr SMESHDS_SubMesh::GetElements( bool reverse ) const
365 {
366   if ( IsComplexSubmesh() )
367     return SMDS_ElemIteratorPtr( new MyElemIterator( mySubMeshes ));
368
369   if ( reverse )
370   {
371     typedef
372       SMDS_SetIterator< const SMDS_MeshElement*,
373                         std::vector< const SMDS_MeshElement* >::const_reverse_iterator > RIter;
374     return SMDS_ElemIteratorPtr( new RIter( myElements.rbegin(), myElements.rend() ));
375   }
376
377   typedef
378     SMDS_SetIterator< const SMDS_MeshElement*,
379                       std::vector< const SMDS_MeshElement* >::const_iterator > FIter;
380   return SMDS_ElemIteratorPtr( new FIter( myElements.begin(), myElements.end() ));
381 }
382
383 //=======================================================================
384 //function : GetNodes
385 //purpose  :
386 //=======================================================================
387
388 SMDS_NodeIteratorPtr SMESHDS_SubMesh::GetNodes( bool reverse ) const
389 {
390   if ( IsComplexSubmesh() )
391     return SMDS_NodeIteratorPtr( new MyNodeIterator( mySubMeshes ));
392
393   if ( reverse )
394   {
395     typedef
396       SMDS_SetIterator< const SMDS_MeshNode*,
397                         std::vector< const SMDS_MeshNode* >::const_reverse_iterator > RIter;
398     return SMDS_NodeIteratorPtr( new RIter( myNodes.rbegin(), myNodes.rend() ));
399   }
400
401   typedef
402     SMDS_SetIterator< const SMDS_MeshNode*,
403                       std::vector< const SMDS_MeshNode* >::const_iterator > FIter;
404   return SMDS_NodeIteratorPtr( new FIter( myNodes.begin(), myNodes.end() ));
405 }
406
407 //=======================================================================
408 //function : Contains
409 //purpose  : check if elem or node is in
410 //=======================================================================
411
412 bool SMESHDS_SubMesh::Contains(const SMDS_MeshElement * ME) const
413 {
414   // DO NOT TRY TO FIND A REMOVED ELEMENT !!
415   //if ( IsComplexSubmesh() || !ME )
416   if (!ME)
417     return false;
418
419   if ( IsComplexSubmesh() )
420   {
421     set<const SMESHDS_SubMesh*>::const_iterator aSubIt = mySubMeshes.begin();
422     for (; aSubIt != mySubMeshes.end(); aSubIt++)
423       if ((*aSubIt)->Contains(ME))
424         return true;
425     return false;
426   }
427
428   if (ME->GetType() == SMDSAbs_Node)
429   {
430     int idInShape = ME->getIdInShape();
431     if ((idInShape >= 0) && (idInShape < (int) myNodes.size()))
432       if (myNodes[idInShape] == ME)
433         return true;
434   }
435   else
436   {
437     int idInShape = ME->getIdInShape();
438     if ((idInShape >= 0) && (idInShape < (int) myElements.size()))
439       if (myElements[idInShape] == ME)
440         return true;
441   }
442   return false;
443 }
444
445 //=======================================================================
446 //function : IsQuadratic
447 //purpose  : Return true if my 1st element is quadratic
448 //=======================================================================
449
450 bool SMESHDS_SubMesh::IsQuadratic() const
451 {
452   if ( IsComplexSubmesh() )
453   {
454     set<const SMESHDS_SubMesh*>::const_iterator aSubIt = mySubMeshes.begin();
455     for (; aSubIt != mySubMeshes.end(); aSubIt++)
456       if ((*aSubIt)->IsQuadratic())
457         return true;
458     return false;
459   }
460
461   for ( size_t i = 0; i < myElements.size(); ++i )
462     if ( myElements[i] )
463       return myElements[i]->IsQuadratic();
464
465   return false;
466 }
467
468 //=======================================================================
469 //function : AddSubMesh
470 //purpose  :
471 //=======================================================================
472
473 void SMESHDS_SubMesh::AddSubMesh( const SMESHDS_SubMesh* theSubMesh )
474 {
475   ASSERT( theSubMesh );
476   mySubMeshes.insert( theSubMesh );
477 }
478
479 //=======================================================================
480 //function : RemoveSubMesh
481 //purpose  : 
482 //=======================================================================
483
484 bool SMESHDS_SubMesh::RemoveSubMesh( const SMESHDS_SubMesh* theSubMesh )
485 {
486   return mySubMeshes.erase( theSubMesh );
487 }
488
489 //=======================================================================
490 //function : RemoveAllSubmeshes
491 //purpose  : 
492 //=======================================================================
493
494 void SMESHDS_SubMesh::RemoveAllSubmeshes()
495 {
496   mySubMeshes.clear();
497 }
498
499 //=======================================================================
500 //function : ContainsSubMesh
501 //purpose  :
502 //=======================================================================
503
504 bool SMESHDS_SubMesh::ContainsSubMesh( const SMESHDS_SubMesh* theSubMesh ) const
505 {
506   return mySubMeshes.find( theSubMesh ) != mySubMeshes.end();
507 }
508
509 //=======================================================================
510 //function : GetSubMeshIterator
511 //purpose  :
512 //=======================================================================
513
514 SMESHDS_SubMeshIteratorPtr SMESHDS_SubMesh::GetSubMeshIterator() const
515 {
516   typedef set<const SMESHDS_SubMesh*>::const_iterator TIterator;
517   return SMESHDS_SubMeshIteratorPtr
518     ( new SMDS_SetIterator< const SMESHDS_SubMesh*, TIterator >( mySubMeshes.begin(),
519                                                                  mySubMeshes.end()));
520 }
521
522 //=======================================================================
523 //function : Clear
524 //purpose  : remove the contents
525 //=======================================================================
526
527 void SMESHDS_SubMesh::Clear()
528 {
529   if ( myParent && myParent->NbNodes() > 0 )
530   {
531     for ( size_t i = 0; i < myElements.size(); ++i )
532     {
533       if ( myElements[i] &&
534            myElements[i]->GetID() > 0 &&
535            myElements[i] == myParent->FindElement( myElements[i]->GetID() )) // not deleted
536         const_cast< SMDS_MeshElement* >( myElements[i] )->setShapeId( 0 );
537     }
538     for ( size_t i = 0; i < myNodes.size(); ++i )
539     {
540       if ( myNodes[i] &&
541            myNodes[i]->GetID() > 0 &&
542            myNodes[i] == myParent->FindNode( myNodes[i]->GetID() )) // not deleted
543         const_cast< SMDS_MeshNode* >( myNodes[i] )->setShapeId( 0 );
544     }
545   }
546
547   clearVector( myElements );
548   clearVector( myNodes );
549   myUnusedIdNodes = 0;
550   myUnusedIdElements = 0;
551   if ( NbSubMeshes() > 0 )
552   {
553     SMESHDS_SubMeshIteratorPtr sub = GetSubMeshIterator();
554     while ( sub->more() ) {
555       if ( SMESHDS_SubMesh* sm = (SMESHDS_SubMesh*) sub->next())
556         sm->Clear();
557     }
558   }
559 }
560
561 int SMESHDS_SubMesh::getSize()
562 {
563   int c = NbNodes();
564   int d = NbElements();
565   return c+d;
566 }
567
568 void SMESHDS_SubMesh::compactList()
569 {
570   if ( myUnusedIdElements > 0 )
571   {
572     std::vector<const SMDS_MeshElement*> newElems;
573     newElems.reserve( myElements.size() - myUnusedIdElements );
574     for ( size_t i = 0; i < myElements.size(); i++)
575       if ( myElements[i] )
576       {
577         SMDS_MeshElement* elem = (SMDS_MeshElement*)myElements[i];
578         elem->setIdInShape( newElems.size() );
579         newElems.push_back( elem );
580       }
581     myElements.swap(newElems);
582     myUnusedIdElements = 0;
583   }
584
585   if ( myUnusedIdNodes > 0 )
586   {
587     std::vector<const SMDS_MeshNode*> newNodes;
588     newNodes.reserve( myNodes.size() - myUnusedIdNodes );
589     for ( size_t i = 0; i < myNodes.size(); i++ )
590       if ( myNodes[i] )
591       {
592         SMDS_MeshNode* node = (SMDS_MeshNode*)myNodes[i];
593         node->setIdInShape( newNodes.size() );
594         newNodes.push_back( node );
595       }
596     myNodes.swap(newNodes);
597     myUnusedIdNodes = 0;
598   }
599 }
600
601 //=======================================================================
602 //function : GetElement
603 //purpose  : Return an element by its IdInShape
604 //=======================================================================
605
606 const SMDS_MeshElement* SMESHDS_SubMesh::GetElement( size_t idInShape ) const
607 {
608   return ( !IsComplexSubmesh() && idInShape < myElements.size() ) ? myElements[idInShape] : 0;
609 }
610
611 //=======================================================================
612 //function : GetElement
613 //purpose  : Return a node by its IdInShape
614 //=======================================================================
615
616 const SMDS_MeshNode* SMESHDS_SubMesh::GetNode( size_t idInShape ) const
617 {
618   return ( !IsComplexSubmesh() && idInShape < myNodes.size() ) ? myNodes[idInShape] : 0;
619 }