Salome HOME
Merge branch 'V9_9_BR'
[modules/smesh.git] / src / SMESH_I / SMESH_Group_i.cxx
1 // Copyright (C) 2007-2022  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 //  SMESH SMESH_I : idl implementation based on 'SMESH' unit's classes
24 //  File   : SMESH_Group_i.cxx
25 //  Author : Sergey ANIKIN, OCC
26 //  Module : SMESH
27 //
28 #include "SMESH_Group_i.hxx"
29
30 #include "SMESHDS_Group.hxx"
31 #include "SMESHDS_GroupOnFilter.hxx"
32 #include "SMESHDS_GroupOnGeom.hxx"
33 #include "SMESHDS_Mesh.hxx"
34 #include "SMESH_Comment.hxx"
35 #include "SMESH_Filter_i.hxx"
36 #include "SMESH_Gen_i.hxx"
37 #include "SMESH_Group.hxx"
38 #include "SMESH_Mesh_i.hxx"
39 #include "SMESH_PythonDump.hxx"
40 #include "SMESH_PreMeshInfo.hxx"
41
42 #include CORBA_SERVER_HEADER(SMESH_Filter)
43
44 #include "utilities.h"
45
46 //=============================================================================
47 /*!
48  *  
49  */
50 //=============================================================================
51
52 SMESH_GroupBase_i::SMESH_GroupBase_i( PortableServer::POA_ptr thePOA,
53                                       SMESH_Mesh_i*           theMeshServant,
54                                       const int               theLocalID )
55 : SALOME::GenericObj_i( thePOA ),
56   myPreMeshInfo(NULL),
57   myNbNodes(-1),
58   myGroupDSTic(0),
59   myMeshServant( theMeshServant ), 
60   myLocalID( theLocalID )
61 {
62   // PAL7962: san -- To ensure correct mapping of servant and correct reference counting in GenericObj_i,
63   // servant activation is performed by SMESH_Mesh_i::createGroup()
64   // thePOA->activate_object( this );
65 }
66
67 SMESH_Group_i::SMESH_Group_i( PortableServer::POA_ptr thePOA,
68                               SMESH_Mesh_i*           theMeshServant,
69                               const int               theLocalID )
70   : SALOME::GenericObj_i( thePOA ),
71     SMESH_GroupBase_i( thePOA, theMeshServant, theLocalID )
72 {
73 }
74
75 SMESH_GroupOnGeom_i::SMESH_GroupOnGeom_i( PortableServer::POA_ptr thePOA,
76                                           SMESH_Mesh_i*           theMeshServant,
77                                           const int               theLocalID )
78   : SALOME::GenericObj_i( thePOA ),
79     SMESH_GroupBase_i( thePOA, theMeshServant, theLocalID )
80 {
81 }
82
83 SMESH_GroupOnFilter_i::SMESH_GroupOnFilter_i( PortableServer::POA_ptr thePOA,
84                                               SMESH_Mesh_i*           theMeshServant,
85                                               const int               theLocalID )
86   : SALOME::GenericObj_i( thePOA ),
87     SMESH_GroupBase_i( thePOA, theMeshServant, theLocalID )
88 {
89 }
90
91 //=============================================================================
92 /*!
93  *  
94  */
95 //=============================================================================
96
97 SMESH_GroupBase_i::~SMESH_GroupBase_i()
98 {
99   if ( myPreMeshInfo ) delete myPreMeshInfo;
100   myPreMeshInfo = NULL;
101 }
102
103 //=======================================================================
104 //function : GetSmeshGroup
105 //purpose  : 
106 //=======================================================================
107
108 ::SMESH_Group* SMESH_GroupBase_i::GetSmeshGroup() const
109 {
110   if ( myMeshServant ) {
111     ::SMESH_Mesh& aMesh = myMeshServant->GetImpl();
112     return aMesh.GetGroup(myLocalID);
113   }
114   return 0;
115 }
116
117 //=======================================================================
118 //function : GetGroupDS
119 //purpose  : 
120 //=======================================================================
121
122 SMESHDS_GroupBase* SMESH_GroupBase_i::GetGroupDS() const
123 {
124   ::SMESH_Group* aGroup = GetSmeshGroup();
125   if ( aGroup )
126     return aGroup->GetGroupDS();
127   return 0;
128 }
129
130 //=============================================================================
131 /*!
132  *  
133  */
134 //=============================================================================
135
136 void SMESH_GroupBase_i::SetName( const char* theName )
137 {
138   // Perform renaming
139   ::SMESH_Group* aGroup = GetSmeshGroup();
140   if (!aGroup) {
141     MESSAGE("can't set name of a vague group");
142     return;
143   }
144
145   if ( aGroup->GetName() && !strcmp( aGroup->GetName(), theName ) )
146     return; // nothing to rename
147
148   aGroup->SetName(theName);
149
150   // Update group name in a study
151   SMESH_Gen_i*              aGen = myMeshServant->GetGen();
152   SMESH::SMESH_GroupBase_var aGrp = _this();
153   SALOMEDS::SObject_var      anSO = aGen->ObjectToSObject( aGrp );
154   if ( !anSO->_is_nil() )
155   {
156     aGen->SetName( anSO, theName );
157
158     // Update Python script
159     SMESH::TPythonDump() <<  anSO << ".SetName( '" << theName << "' )";
160   }
161 }
162
163 //=============================================================================
164 /*!
165  *  
166  */
167 //=============================================================================
168
169 char* SMESH_GroupBase_i::GetName()
170 {
171   ::SMESH_Group* aGroup = GetSmeshGroup();
172   if (aGroup)
173     return CORBA::string_dup( aGroup->GetName() );
174   return CORBA::string_dup( "NO_NAME" );
175 }
176
177 //=============================================================================
178 /*!
179  *
180  */
181 //=============================================================================
182
183 SMESH::ElementType SMESH_GroupBase_i::GetType()
184 {
185   SMESHDS_GroupBase* aGroupDS = GetGroupDS();
186   if (aGroupDS) {
187     SMDSAbs_ElementType aSMDSType = aGroupDS->GetType();
188     SMESH::ElementType aType;
189     switch (aSMDSType) {
190     case SMDSAbs_Node:      aType = SMESH::NODE;   break;
191     case SMDSAbs_Edge:      aType = SMESH::EDGE;   break;
192     case SMDSAbs_Face:      aType = SMESH::FACE;   break;
193     case SMDSAbs_Volume:    aType = SMESH::VOLUME; break;
194     case SMDSAbs_0DElement: aType = SMESH::ELEM0D; break;
195     case SMDSAbs_Ball:      aType = SMESH::BALL;   break;
196     default:                aType = SMESH::ALL;    break;
197     }
198     return aType;
199   }
200   return SMESH::ALL;
201 }
202
203
204 //=============================================================================
205 /*!
206  *  
207  */
208 //=============================================================================
209
210 SMESH::smIdType SMESH_GroupBase_i::Size()
211 {
212   if ( myPreMeshInfo )
213     return GetType() == SMESH::NODE ? myPreMeshInfo->NbNodes() : myPreMeshInfo->NbElements();
214
215   SMESHDS_GroupBase* aGroupDS = GetGroupDS();
216   if (aGroupDS)
217     return aGroupDS->Extent();
218   return 0;
219 }
220
221 //=============================================================================
222 /*!
223  *  
224  */
225 //=============================================================================
226
227 CORBA::Boolean SMESH_GroupBase_i::IsEmpty()
228 {
229   if ( myPreMeshInfo )
230     return Size() == 0;
231
232   SMESHDS_GroupBase* aGroupDS = GetGroupDS();
233   if (aGroupDS)
234     return aGroupDS->IsEmpty();
235   return true;
236 }
237
238 //=============================================================================
239 /*
240  * Return \c true if \c this group depends on the \a other via
241  * FT_BelongToMeshGroup predicate or vice versa
242  */
243 //=============================================================================
244
245 bool SMESH_GroupBase_i::IsInDependency( SMESH::SMESH_GroupBase_ptr other )
246 {
247   if ( NotifyerAndWaiter* nw = SMESH::DownCast< NotifyerAndWaiter* >( other ))
248     return ( nw->ContainModifWaiter( this ) || this->ContainModifWaiter( nw ));
249
250   return false;
251 }
252
253 //=============================================================================
254 /*!
255  *  
256  */
257 //=============================================================================
258
259 void SMESH_Group_i::Clear()
260 {
261   if ( myPreMeshInfo )
262     myPreMeshInfo->FullLoadFromFile();
263
264   // Update Python script
265   SMESH::TPythonDump() << SMESH::SMESH_Group_var(_this()) << ".Clear()";
266
267   // Clear the group
268   SMESHDS_Group* aGroupDS = dynamic_cast<SMESHDS_Group*>( GetGroupDS() );
269   if (aGroupDS) {
270     aGroupDS->Clear();
271     return;
272   }
273   Modified(); // notify dependent Filter with FT_BelongToMeshGroup criterion
274 }
275
276 //=============================================================================
277 /*!
278  *  
279  */
280 //=============================================================================
281
282 CORBA::Boolean SMESH_GroupBase_i::Contains( SMESH::smIdType theID )
283 {
284   if ( myPreMeshInfo )
285     myPreMeshInfo->FullLoadFromFile();
286
287   SMESHDS_GroupBase* aGroupDS = GetGroupDS();
288   if (aGroupDS)
289     return aGroupDS->Contains(theID);
290   return false;
291 }
292
293 //=============================================================================
294 /*!
295  *  
296  */
297 //=============================================================================
298
299 SMESH::smIdType  SMESH_Group_i::Add( const SMESH::smIdType_array& theIDs )
300 {
301   if ( myPreMeshInfo )
302     myPreMeshInfo->FullLoadFromFile();
303
304   // Update Python script
305   SMESH::TPythonDump() << "nbAdd = " << SMESH::SMESH_Group_var(_this()) << ".Add( " << theIDs << " )";
306
307   // Add elements to the group
308   SMESHDS_Group* aGroupDS = dynamic_cast<SMESHDS_Group*>( GetGroupDS() );
309   if (aGroupDS) {
310     int nbAdd = 0;
311     for ( CORBA::ULong i = 0; i < theIDs.length(); i++) {
312       int anID = (int) theIDs[i];
313       if ( aGroupDS->Add( anID ))
314         nbAdd++;
315     }
316     if ( nbAdd )
317       Modified(); // notify dependent Filter with FT_BelongToMeshGroup criterion
318     return nbAdd;
319   }
320   MESSAGE("attempt to add elements to a vague group");
321   return 0;
322 }
323
324 //=============================================================================
325 /*!
326  *
327  */
328 //=============================================================================
329
330 SMESH::smIdType  SMESH_Group_i::Remove( const SMESH::smIdType_array& theIDs )
331 {
332   if ( myPreMeshInfo )
333     myPreMeshInfo->FullLoadFromFile();
334
335   // Update Python script
336   SMESH::TPythonDump() << "nbDel = " << SMESH::SMESH_Group_var(_this())
337                 << ".Remove( " << theIDs << " )";
338
339   // Remove elements from the group
340   SMESHDS_Group* aGroupDS = dynamic_cast<SMESHDS_Group*>( GetGroupDS() );
341   if (aGroupDS) {
342     int nbDel = 0;
343     for ( CORBA::ULong i = 0; i < theIDs.length(); i++ ) {
344       int anID = (int) theIDs[i];
345       if ( aGroupDS->Remove( anID ))
346         nbDel++;
347     }
348     if ( nbDel )
349       Modified(); // notify dependent Filter with FT_BelongToMeshGroup criterion
350     return nbDel;
351   }
352   MESSAGE("attempt to remove elements from a vague group");
353   return 0;
354 }
355
356 //=============================================================================
357 /*!
358  *
359  */
360 //=============================================================================
361
362 typedef bool (SMESHDS_Group::*TFunChangeGroup)(const smIdType);
363
364 CORBA::Long 
365 ChangeByPredicate( SMESH::Predicate_i*       thePredicate,
366                    SMESHDS_GroupBase*        theGroupBase,
367                    SMESH::NotifyerAndWaiter* theGroupImpl,
368                    TFunChangeGroup           theFun)
369 {
370   CORBA::Long aNb = 0;
371   if(SMESHDS_Group* aGroupDS = dynamic_cast<SMESHDS_Group*>(theGroupBase)){
372     SMESH::Controls::Filter::TIdSequence aSequence;
373     const SMDS_Mesh* aMesh = theGroupBase->GetMesh();
374     SMESH::Filter_i::GetElementsId(thePredicate,aMesh,aSequence);
375     
376     CORBA::Long i = 0, iEnd = aSequence.size();
377     for(; i < iEnd; i++)
378       if((aGroupDS->*theFun)(aSequence[i]))
379         aNb++;
380     if ( aNb )
381       theGroupImpl->Modified();
382     return aNb;
383   }
384   return aNb;
385 }
386
387 SMESH::smIdType  
388 SMESH_Group_i::
389 AddByPredicate( SMESH::Predicate_ptr thePredicate )
390 {
391   if ( myPreMeshInfo )
392     myPreMeshInfo->FullLoadFromFile();
393
394   if(SMESH::Predicate_i* aPredicate = SMESH::GetPredicate(thePredicate)){
395     SMESH::TPythonDump() << SMESH::SMESH_Group_var(_this())
396                          << ".AddByPredicate( " << aPredicate << " )";
397     return ChangeByPredicate( aPredicate, GetGroupDS(), this, &SMESHDS_Group::Add );
398   }
399   return 0;
400 }
401
402 SMESH::smIdType  
403 SMESH_Group_i::
404 RemoveByPredicate( SMESH::Predicate_ptr thePredicate )
405 {
406   if ( myPreMeshInfo )
407     myPreMeshInfo->FullLoadFromFile();
408
409   if(SMESH::Predicate_i* aPredicate = SMESH::GetPredicate(thePredicate)){
410     SMESH::TPythonDump() << SMESH::SMESH_Group_var(_this())
411                          << ".RemoveByPredicate( " << aPredicate << " )";
412     return ChangeByPredicate(aPredicate,GetGroupDS(),this, &SMESHDS_Group::Remove);
413   }
414   return 0;
415 }
416
417 SMESH::smIdType  SMESH_Group_i::AddFrom( SMESH::SMESH_IDSource_ptr theSource )
418 {
419   if ( myPreMeshInfo )
420     myPreMeshInfo->FullLoadFromFile();
421
422   SMESH::TPythonDump pd;
423   long prevNb = Size();
424   SMESHDS_Group* aGroupDS = dynamic_cast<SMESHDS_Group*>( GetGroupDS() );
425   if (aGroupDS) {
426     if ( SMDS_ElemIteratorPtr elemIt = SMESH_Mesh_i::GetElements( theSource, GetType() ))
427       while ( elemIt->more() )
428         aGroupDS->SMDSGroup().Add( elemIt->next() );
429   }
430
431   // Update Python script
432   pd << "nbAdd = " << SMESH::SMESH_Group_var(_this()) << ".AddFrom( " << theSource << " )";
433
434   if ( prevNb != Size() )
435     Modified(); // notify dependent Filter with FT_BelongToMeshGroup criterion
436
437   return Size() - prevNb;
438 }
439
440 //=============================================================================
441 /*!
442  * Return ID of theIndex-th group item
443  */
444 //=============================================================================
445
446 SMESH::smIdType  SMESH_GroupBase_i::GetID( SMESH::smIdType theIndex )
447 {
448   if ( myPreMeshInfo )
449     myPreMeshInfo->FullLoadFromFile();
450
451   SMESHDS_GroupBase* aGroupDS = GetGroupDS();
452   if (aGroupDS)
453     return aGroupDS->GetID(theIndex);
454   MESSAGE("attempt to iterate on a vague group");
455   return -1;
456 }
457
458 //=============================================================================
459 /*!
460  *  
461  */
462 //=============================================================================
463
464 SMESH::smIdType_array* SMESH_GroupBase_i::GetListOfID()
465 {
466   if ( myPreMeshInfo )
467     myPreMeshInfo->FullLoadFromFile();
468
469   SMESH::smIdType_array_var aRes = new SMESH::smIdType_array();
470   SMESHDS_GroupBase* aGroupDS = GetGroupDS();
471   if (aGroupDS)
472   {
473     smIdType aSize = aGroupDS->Extent();
474     aRes->length(aSize);
475     SMDS_ElemIteratorPtr it = aGroupDS->GetElements();
476     for (::smIdType i = 0; it->more(); i++)
477       aRes[i] = it->next()->GetID();
478
479     if ( 0 < aSize && aSize < 100 ) // for comfortable testing ;)
480       std::sort( &aRes[0], &aRes[0]+aSize );
481   }
482   return aRes._retn();
483 }
484
485 namespace
486 {
487   //================================================================================
488   /*!
489    * \brief return nodes of elements pointered by iterator
490    */
491   //================================================================================
492
493   void getNodesOfElements(SMDS_ElemIteratorPtr             elemIt,
494                           std::set<const SMDS_MeshNode* >& nodes)
495   {
496     while ( elemIt->more() )
497     {
498       const SMDS_MeshElement* e = elemIt->next();
499       nodes.insert( e->begin_nodes(), e->end_nodes() );
500     }
501   }
502 }
503   
504 //================================================================================
505 /*!
506  * \brief return the number of nodes of cells included to the group
507  */
508 //================================================================================
509
510 SMESH::smIdType  SMESH_GroupBase_i::GetNumberOfNodes()
511 {
512   if ( GetType() == SMESH::NODE )
513     return Size();
514
515   if ( myPreMeshInfo )
516     myPreMeshInfo->FullLoadFromFile();
517
518   if ( SMESHDS_GroupBase* g = GetGroupDS())
519   {
520     if ( myNbNodes < 0 || g->GetTic() != myGroupDSTic )
521     {      
522       std::set<const SMDS_MeshNode* > nodes;
523       getNodesOfElements( g->GetElements(), nodes );
524       myNbNodes = nodes.size();
525       myGroupDSTic = g->GetTic();
526     }
527   }
528   return myNbNodes;
529 }
530
531 //================================================================================
532 /*!
533  * \brief Return true if GetNumberOfNodes() won't take a long time for computation
534  */
535 //================================================================================
536
537 CORBA::Boolean SMESH_GroupBase_i::IsNodeInfoAvailable()
538 {
539   if ( GetType() == SMESH::NODE/* || Size() < 100000 */)
540     return true;
541   if ( myPreMeshInfo )
542     return false;
543   if ( SMESHDS_GroupBase* g = GetGroupDS())
544     return ( myNbNodes > -1 && g->GetTic() == myGroupDSTic);
545   return false;
546 }
547
548 //================================================================================
549 /*!
550  * \brief Return IDs of nodes of cells included to the group
551  */
552 //================================================================================
553
554 SMESH::smIdType_array* SMESH_GroupBase_i::GetNodeIDs()
555 {
556   if ( GetType() == SMESH::NODE )
557     return GetListOfID();
558
559   if ( myPreMeshInfo )
560     myPreMeshInfo->FullLoadFromFile();
561
562   SMESH::smIdType_array_var aRes = new SMESH::smIdType_array();
563   if ( SMESHDS_GroupBase* g = GetGroupDS())
564   {
565     std::set<const SMDS_MeshNode* > nodes;
566     getNodesOfElements( g->GetElements(), nodes );
567     aRes->length( nodes.size() );
568     std::set<const SMDS_MeshNode*>::iterator nIt = nodes.begin(), nEnd = nodes.end();
569     for ( int i = 0; nIt != nEnd; ++nIt, ++i )
570       aRes[i] = (*nIt)->GetID();
571   }
572   return aRes._retn();
573 }
574
575 //=============================================================================
576 /*!
577  *  
578  */
579 //=============================================================================
580 SMESH::SMESH_Mesh_ptr SMESH_GroupBase_i::GetMesh()
581 {
582   SMESH::SMESH_Mesh_var aMesh;
583   if ( myMeshServant )
584     aMesh = myMeshServant->_this();
585   return aMesh._retn();
586 }
587
588 //=======================================================================
589 //function : GetShape
590 //purpose  : 
591 //=======================================================================
592
593 GEOM::GEOM_Object_ptr SMESH_GroupOnGeom_i::GetShape()
594 {
595   GEOM::GEOM_Object_var aGeomObj;
596   SMESHDS_GroupOnGeom* aGroupDS = dynamic_cast<SMESHDS_GroupOnGeom*>( GetGroupDS() );
597   if ( aGroupDS ) {
598     SMESH_Gen_i* aGen = GetMeshServant()->GetGen();
599     aGeomObj = aGen->ShapeToGeomObject( aGroupDS->GetShape() );
600   }
601   return aGeomObj._retn();
602 }
603
604 //=============================================================================
605 /*!
606  *
607  */
608 //=============================================================================
609 SALOMEDS::Color SMESH_GroupBase_i::GetColor()
610 {
611   SMESHDS_GroupBase* aGroupDS = GetGroupDS();
612   if (aGroupDS)
613   {
614     Quantity_Color aQColor = aGroupDS->GetColor();
615     SALOMEDS::Color aColor;
616     aColor.R = aQColor.Red();
617     aColor.G = aQColor.Green();
618     aColor.B = aQColor.Blue();
619
620     return aColor;
621   }
622   return SALOMEDS::Color();
623 }
624
625 //=============================================================================
626 /*!
627  *
628  */
629 //=============================================================================
630 void SMESH_GroupBase_i::SetColor(const SALOMEDS::Color& color)
631 {
632   SMESHDS_GroupBase* aGroupDS = GetGroupDS();
633   if (aGroupDS)
634   {
635     Quantity_Color aQColor( color.R, color.G, color.B, Quantity_TOC_RGB );
636     Quantity_Color oldColor = aGroupDS->GetColor();
637     if ( oldColor != aQColor )
638     {
639       aGroupDS->SetColor(aQColor);
640       SMESH::TPythonDump()<< SMESH::SMESH_GroupBase_var(_this())
641                           << ".SetColor( SALOMEDS.Color( "
642                           <<color.R<<", "<<color.G<<", "<<color.B<<" ))";
643     }
644   }
645 }
646
647 //=============================================================================
648 /*!
649  *
650  */
651 //=============================================================================
652 CORBA::Long  SMESH_GroupBase_i::GetColorNumber()
653 {
654   SMESHDS_GroupBase* aGroupDS = GetGroupDS();
655   if (aGroupDS)
656     return aGroupDS->GetColorGroup();
657   MESSAGE("get color number of a group");
658   return 0;
659 }
660
661 //=============================================================================
662 /*!
663  *
664  */
665 //=============================================================================
666 void SMESH_GroupBase_i::SetColorNumber(CORBA::Long color)
667 {
668   SMESHDS_GroupBase* aGroupDS = GetGroupDS();
669   if (aGroupDS)
670   {
671     aGroupDS->SetColorGroup(color);
672     SMESH::TPythonDump()<<SMESH::SMESH_GroupBase_var(_this())<<".SetColorNumber( "<<color<<" )";
673   }
674   return ;
675 }
676
677 //=============================================================================
678 /*
679  * Return number of mesh elements of each \a SMESH::EntityType
680  * Result array of number of elements per \a SMESH::EntityType
681  * Inherited from SMESH_IDSource
682  */
683 //=============================================================================
684
685 SMESH::smIdType_array* SMESH_GroupBase_i::GetMeshInfo()
686 {
687   if ( myPreMeshInfo )
688     return myPreMeshInfo->GetMeshInfo();
689
690   SMESH::smIdType_array_var aRes = new SMESH::smIdType_array();
691   aRes->length(SMESH::Entity_Last);
692   for (int i = SMESH::Entity_Node; i < SMESH::Entity_Last; i++)
693     aRes[i] = 0;
694
695   if ( SMESHDS_GroupBase* g = GetGroupDS())
696   {
697     if ( g->GetType() == SMDSAbs_Node /*|| ( myNbNodes > -1 && g->GetTic() == myGroupDSTic)*/)
698       aRes[ SMDSEntity_Node ] = GetNumberOfNodes();
699
700     if ( g->GetType() != SMDSAbs_Node )
701       SMESH_Mesh_i::CollectMeshInfo( g->GetElements(), aRes);
702   }
703
704   return aRes._retn();
705 }
706
707 //=============================================================================
708 /*
709  * Return number of mesh elements of each \a ElementType
710  */
711 //=============================================================================
712
713 SMESH::smIdType_array* SMESH_GroupBase_i::GetNbElementsByType()
714 {
715   SMESH::smIdType_array_var aRes = new SMESH::smIdType_array();
716   aRes->length(SMESH::NB_ELEMENT_TYPES);
717   for (int i = 0; i < SMESH::NB_ELEMENT_TYPES; i++)
718     aRes[ i ] = 0;
719
720   if ( myPreMeshInfo )
721     aRes[ GetType() ] = myPreMeshInfo->NbElements( SMDSAbs_ElementType( GetType() ));
722   else
723     aRes[ GetType() ] = Size();
724
725   return aRes._retn();  
726 }
727
728 //=======================================================================
729 //function : GetIDs
730 //purpose  : Return ids of members
731 //=======================================================================
732
733 SMESH::smIdType_array* SMESH_GroupBase_i::GetIDs()
734 {
735   return GetListOfID();
736 }
737
738 //=======================================================================
739 //function : GetTypes
740 //purpose  : Return types of elements it contains
741 //=======================================================================
742
743 SMESH::array_of_ElementType* SMESH_GroupBase_i::GetTypes()
744 {
745   SMESH::array_of_ElementType_var types = new SMESH::array_of_ElementType;
746   if ( !IsEmpty() )
747   {
748     types->length( 1 );
749     types[0] = GetType();
750   }
751   return types._retn();
752 }
753
754 //=======================================================================
755 //function : IsMeshInfoCorrect
756 //purpose  : * Return false if GetMeshInfo() returns incorrect information that may
757 //           * happen if mesh data is not yet fully loaded from the file of study.
758 //=======================================================================
759
760 bool SMESH_GroupBase_i::IsMeshInfoCorrect()
761 {
762   return myPreMeshInfo ? myPreMeshInfo->IsMeshInfoCorrect() : true;
763 }
764
765 //=======================================================================
766 //function : GetVtkUgStream
767 //purpose  : Return data vtk unstructured grid (not implemented)
768 //=======================================================================
769
770 SALOMEDS::TMPFile* SMESH_GroupBase_i::GetVtkUgStream()
771 {
772   SALOMEDS::TMPFile_var SeqFile;
773   return SeqFile._retn();
774 }
775
776 //================================================================================
777 /*!
778  * \brief Retrieves the predicate from the filter
779  */
780 //================================================================================
781
782 SMESH_PredicatePtr SMESH_GroupOnFilter_i::GetPredicate( SMESH::Filter_ptr filter )
783 {
784   SMESH_PredicatePtr predicate;
785
786   if ( SMESH::Filter_i* filt_i = SMESH::DownCast< SMESH::Filter_i* >( filter ))
787     if ( SMESH::Predicate_i* predic_i= filt_i->GetPredicate_i() )
788       predicate = predic_i->GetPredicate();
789
790   return predicate;
791 }
792
793 //================================================================================
794 /*!
795  * \brief Sets the filter defining group contents
796  */
797 //================================================================================
798
799 void SMESH_GroupOnFilter_i::SetFilter(SMESH::Filter_ptr theFilter)
800 {
801   if ( myFilter->_is_equivalent( theFilter ))
802     return;
803
804   if ( myPreMeshInfo )
805     myPreMeshInfo->FullLoadFromFile();
806
807   if ( ! myFilter->_is_nil() )
808     myFilter->UnRegister();
809
810   myFilter = SMESH::Filter::_duplicate( theFilter );
811
812   if ( !myFilter->_is_nil() )
813   {
814     myFilter->Register();
815
816     if ( SMESH::Filter_i* f = SMESH::DownCast< SMESH::Filter_i* >( myFilter ))
817     {
818       // make filter notify me about change of either a predicate or a base group
819       f->FindBaseObjects();
820
821       if ( f->ContainModifWaiter( this ) ||
822            this->ContainModifWaiter( f ))
823       {
824         SetFilter( SMESH::Filter::_nil() );
825         THROW_SALOME_CORBA_EXCEPTION( "Cyclic dependency between Groups on Filter",
826                                       SALOME::BAD_PARAM );
827       }
828       f->AddModifWaiter( this );
829     }
830     myFilter->SetMesh( SMESH::SMESH_Mesh::_nil() ); // to UnRegister() the mesh
831   }
832
833   if ( SMESHDS_GroupOnFilter* grDS = dynamic_cast< SMESHDS_GroupOnFilter*>( GetGroupDS() ))
834   {
835     grDS->SetPredicate( GetPredicate( myFilter ));
836     Modified(); // notify dependent Filter with FT_BelongToMeshGroup criterion
837   }
838
839   SMESH::SMESH_GroupOnFilter_var me = _this();
840
841   // mark the group valid after edition
842   GetMeshServant()->GetGen()->HighLightInvalid( me, false );
843
844
845   SMESH::TPythonDump()<< me <<".SetFilter( "<< theFilter <<" )";
846 }
847
848 //================================================================================
849 /*!
850  * \brief Return the filter defining group contents
851  */
852 //================================================================================
853
854 SMESH::Filter_ptr SMESH_GroupOnFilter_i::GetFilter()
855 {
856   SMESH::Filter_var f = myFilter;
857   SMESH::TPythonDump() << f << " = " << SMESH::SMESH_GroupOnFilter_var(_this()) << ".GetFilter()";
858   return f._retn();
859 }
860
861 //================================================================================
862 /*!
863  * @return true if group contents is computed
864  */
865 //================================================================================
866
867 CORBA::Boolean SMESH_GroupOnFilter_i::IsUpToDate()
868 {
869   if ( myPreMeshInfo )
870     return false;
871
872   if ( SMESHDS_GroupOnFilter* grDS = dynamic_cast< SMESHDS_GroupOnFilter*>( GetGroupDS() ))
873     return grDS->IsUpToDate();
874
875   return false;
876 }
877
878 //=======================================================================
879 //function : IsMeshInfoCorrect
880 //purpose  : Return false in two cases: 1) if mesh not loaded and GetMeshInfo() returns
881 //           incorrect information 2) mesh loaded but group contents is not computed
882 //=======================================================================
883
884 bool SMESH_GroupOnFilter_i::IsMeshInfoCorrect()
885 {
886   return myPreMeshInfo ? myPreMeshInfo->IsMeshInfoCorrect() : IsUpToDate();
887 }
888
889 //=======================================================================
890 //function : GetIDs
891 //purpose  : Return ids of members
892 //=======================================================================
893
894 SMESH::smIdType_array* SMESH_GroupOnFilter_i::GetListOfID()
895 {
896   if ( myPreMeshInfo )
897     myPreMeshInfo->FullLoadFromFile();
898
899   SMESH::smIdType_array_var aRes = new SMESH::smIdType_array();
900   SMESHDS_GroupBase* aGroupDS = GetGroupDS();
901   if ( SMESHDS_GroupOnFilter* grDS = dynamic_cast< SMESHDS_GroupOnFilter*>( GetGroupDS() ))
902   {
903     const SMDS_MeshInfo& meshInfo = aGroupDS->GetMesh()->GetMeshInfo();
904     aRes->length( meshInfo.NbElements( aGroupDS->GetType() ));
905     if ( aRes->length() ) // else aRes[0] -> SIGSEGV
906       aRes->length( grDS->GetElementIds( &aRes[0] ));
907
908     if ( 0 < aRes->length() && aRes->length() < 100 ) // for comfortable testing ;)
909       std::sort( &aRes[0], &aRes[0] + aRes->length() );
910   }
911   return aRes._retn();
912 }
913
914 //=============================================================================
915 /*!
916  * Return statistic of mesh elements
917  * Result array of number enityties
918  * Inherited from SMESH_IDSource
919  */
920 //=============================================================================
921
922 SMESH::smIdType_array* SMESH_GroupOnFilter_i::GetMeshInfo()
923 {
924   if ( myPreMeshInfo )
925     return myPreMeshInfo->GetMeshInfo();
926
927   SMESH::smIdType_array_var aRes = new SMESH::smIdType_array();
928   aRes->length(SMESH::Entity_Last);
929   for (int i = SMESH::Entity_Node; i < SMESH::Entity_Last; i++)
930     aRes[i] = 0;
931
932   if ( SMESHDS_GroupBase* g = GetGroupDS())
933   {
934     if ( g->GetType() == SMDSAbs_Node /*|| ( myNbNodes > -1 && g->GetTic() == myGroupDSTic)*/)
935       aRes[ SMDSEntity_Node ] = GetNumberOfNodes();
936
937     if ( g->GetType() != SMDSAbs_Node )
938     {
939       std::vector< smIdType > nbElems = static_cast< SMESHDS_GroupOnFilter* >( g )->GetMeshInfo();
940       for ( size_t i = SMESH::Entity_Node; i < SMESH::Entity_Last; i++)
941         if ( i < nbElems.size() )
942           aRes[i] = nbElems[ i ];
943     }
944   }
945
946   return aRes._retn();
947 }
948
949 #define SEPAR '^'
950
951 //================================================================================
952 /*!
953  * \brief Return a string to be used to store group definition in the study
954  */
955 //================================================================================
956
957 std::string SMESH_GroupOnFilter_i::FilterToString() const
958 {
959   SMESH_Comment result;
960   SMESH::Filter::Criteria_var criteria;
961   if ( !myFilter->_is_nil() && myFilter->GetCriteria( criteria.out() ))
962   {
963     result << criteria->length() << SEPAR;
964     for ( unsigned i = 0; i < criteria->length(); ++i )
965     {
966       SMESH::Filter::Criterion& crit = criteria[ i ];
967
968       if ( SMESH::FunctorType( crit.Type ) == SMESH::FT_BelongToMeshGroup &&
969            crit.ThresholdID.in() && crit.ThresholdID.in()[0] )
970       {
971         CORBA::Object_var obj = SMESH_Gen_i::GetORB()->string_to_object( crit.ThresholdID );
972         if ( SMESH_GroupBase_i * g = SMESH::DownCast< SMESH_GroupBase_i*>( obj ))
973           if ( SMESHDS_GroupBase* gDS = g->GetGroupDS() )
974             crit.ThresholdID = gDS->GetStoreName();
975       }
976       // write FunctorType as string but not as number to assure correct
977       // persistence if enum FunctorType is modified by insertion in the middle
978       result << SMESH::FunctorTypeToString( SMESH::FunctorType( crit.Type ))    << SEPAR;
979       result << SMESH::FunctorTypeToString( SMESH::FunctorType( crit.Compare )) << SEPAR;
980       result << crit.Threshold                                                  << SEPAR;
981       result << crit.ThresholdStr                                               << SEPAR;
982       result << crit.ThresholdID                                                << SEPAR;
983       result << SMESH::FunctorTypeToString( SMESH::FunctorType( crit.UnaryOp )) << SEPAR;
984       result << SMESH::FunctorTypeToString( SMESH::FunctorType( crit.BinaryOp ))<< SEPAR;
985       result << crit.Tolerance                                                  << SEPAR;
986       result << crit.TypeOfElement                                              << SEPAR;
987       result << crit.Precision                                                  << SEPAR;
988     }
989   }
990   return result;
991 }
992
993 //================================================================================
994 /*!
995  * \brief Restore the filter by the persistent string
996  */
997 //================================================================================
998
999 SMESH::Filter_ptr SMESH_GroupOnFilter_i::StringToFilter(const std::string& thePersistStr )
1000 {
1001   SMESH::Filter_var filter;
1002
1003   // divide thePersistStr into sub-strings
1004   std::vector< std::string > strVec;
1005   std::string::size_type from = 0, to;
1006   while ( from < thePersistStr.size() )
1007   {
1008     to = thePersistStr.find( SEPAR, from );
1009     if ( to == std::string::npos )
1010       break;
1011     strVec.push_back( thePersistStr.substr( from, to-from ));
1012     from = to+1;
1013   }
1014   if ( strVec.empty() || strVec[0] == "0" )
1015     return filter._retn();
1016 #undef SEPAR
1017
1018   // create Criteria
1019   int nbCrit = atoi( strVec[0].c_str() );
1020   SMESH::Filter::Criteria_var criteria = new SMESH::Filter::Criteria;
1021   criteria->length( nbCrit );
1022   int nbStrPerCrit = ( strVec.size() - 1 ) / nbCrit;
1023   for ( int i = 0; i < nbCrit; ++i )
1024   {
1025     SMESH::Filter::Criterion& crit = criteria[ i ];
1026     int iStr = 1 + i * nbStrPerCrit;
1027     crit.Type         = SMESH::StringToFunctorType( strVec[ iStr++ ].c_str() );
1028     crit.Compare      = SMESH::StringToFunctorType( strVec[ iStr++ ].c_str() );
1029     crit.Threshold    = atof(                       strVec[ iStr++ ].c_str() );
1030     crit.ThresholdStr =                             strVec[ iStr++ ].c_str();
1031     crit.ThresholdID  =                             strVec[ iStr++ ].c_str();
1032     crit.UnaryOp      = SMESH::StringToFunctorType( strVec[ iStr++ ].c_str() );
1033     crit.BinaryOp     = SMESH::StringToFunctorType( strVec[ iStr++ ].c_str() );
1034     crit.Tolerance    = atof(                       strVec[ iStr++ ].c_str() );
1035     crit.TypeOfElement= SMESH::ElementType( atoi(   strVec[ iStr++ ].c_str() ));
1036     crit.Precision    = atoi(                       strVec[ iStr++ ].c_str() );
1037   }
1038
1039   // create a filter
1040   SMESH::TPythonDump pd;
1041   SMESH::FilterManager_i* aFilterMgr = new SMESH::FilterManager_i();
1042   filter = aFilterMgr->CreateFilter();
1043   filter->SetCriteria( criteria.inout() );
1044   
1045   aFilterMgr->UnRegister();
1046
1047   pd << ""; // to avoid optimizing pd out
1048
1049   return filter._retn();
1050 }
1051
1052 //================================================================================
1053 /*!
1054  * \brief Destructor of SMESH_GroupOnFilter_i
1055  */
1056 //================================================================================
1057
1058 SMESH_GroupOnFilter_i::~SMESH_GroupOnFilter_i()
1059 {
1060   if ( ! myFilter->_is_nil() )
1061   {
1062     SMESH::DownCast< SMESH::Filter_i* >( myFilter )->RemoveModifWaiter( this );
1063     myFilter->UnRegister();
1064   }
1065 }
1066
1067 //================================================================================
1068 /*!
1069  * \brief Method called when a predicate of myFilter changes
1070  */
1071 //================================================================================
1072
1073 void SMESH_GroupOnFilter_i::OnBaseObjModified(NotifyerAndWaiter* /*filter*/, bool /*removed*/)
1074 {
1075   if ( myPreMeshInfo )
1076     myPreMeshInfo->FullLoadFromFile();
1077
1078   if ( SMESHDS_GroupOnFilter* grDS = dynamic_cast< SMESHDS_GroupOnFilter*>( GetGroupDS() ))
1079     grDS->SetPredicate( GetPredicate( myFilter )); // group resets its cache
1080 }
1081