Salome HOME
Issue 0020788: EDF 1339 SMESH : Crash after enabling "Auto Color" feature in attached...
[modules/smesh.git] / src / SMESHGUI / SMESHGUI_VTKUtils.cxx
1 //  Copyright (C) 2007-2008  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.
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 // SMESH SMESHGUI : GUI for SMESH component
23 // File   : SMESHGUI_VTKUtils.cxx
24 // Author : Open CASCADE S.A.S.
25 // SMESH includes
26 //
27 #include "SMESHGUI_VTKUtils.h"
28
29 #include "SMESHGUI.h"
30 #include "SMESHGUI_Utils.h"
31 #include "SMESHGUI_Filter.h"
32
33 #include <SMESH_Actor.h>
34 #include <SMESH_ActorUtils.h>
35 #include <SMESH_ObjectDef.h>
36 #include <SMDS_Mesh.hxx>
37
38 // SALOME GUI includes
39 #include <SUIT_Desktop.h>
40 #include <SUIT_Session.h>
41 #include <SUIT_MessageBox.h>
42 #include <SUIT_ViewManager.h>
43 #include <SUIT_ResourceMgr.h>
44
45 #include <SALOME_ListIO.hxx>
46 #include <SALOME_ListIteratorOfListIO.hxx>
47
48 #include <SVTK_Selector.h>
49 #include <SVTK_ViewModel.h>
50 #include <SVTK_ViewWindow.h>
51
52 #include <VTKViewer_Algorithm.h>
53
54 #include <LightApp_SelectionMgr.h>
55 #include <SalomeApp_Application.h>
56 #include <SalomeApp_Study.h>
57
58 // SALOME KERNEL includes
59 #include <utilities.h>
60
61 // IDL includes
62 #include <SALOMEconfig.h>
63 #include CORBA_CLIENT_HEADER(SMESH_Mesh)
64 #include CORBA_CLIENT_HEADER(SMESH_Group)
65
66 // VTK includes
67 #include <vtkRenderer.h>
68 #include <vtkActorCollection.h>
69 #include <vtkUnstructuredGrid.h>
70
71 // OCCT includes
72 #include <TColStd_IndexedMapOfInteger.hxx>
73 #include <Standard_ErrorHandler.hxx>
74
75 namespace SMESH
76 {
77   typedef std::map<TKeyOfVisualObj,TVisualObjPtr> TVisualObjCont;
78   static TVisualObjCont VISUAL_OBJ_CONT;
79
80   //=============================================================================
81   /*!
82    * \brief Allocate some memory at construction and release it at destruction.
83    * Is used to be able to continue working after mesh generation or visualization
84    * break due to lack of memory
85    */
86   //=============================================================================
87
88   struct MemoryReserve
89   {
90     char* myBuf;
91     MemoryReserve(): myBuf( new char[1024*1024*1] ){} // 1M
92     void Free() { if (myBuf) { delete [] myBuf; myBuf = 0; }}
93     ~MemoryReserve() { Free(); }
94   };
95   static MemoryReserve* theVISU_MemoryReserve = new MemoryReserve;
96
97   //================================================================================
98   /*!
99    * \brief Remove VisualObj and its actor from all views
100    */
101   //================================================================================
102
103   void RemoveVisualObjectWithActors( const char* theEntry )
104   {
105     SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>
106       ( SUIT_Session::session()->activeApplication() );
107     SUIT_ViewManager* aViewManager =
108       app ? app->getViewManager(SVTK_Viewer::Type(), true) : 0;
109     if ( aViewManager ) {
110       QVector<SUIT_ViewWindow*> views = aViewManager->getViews();
111       for ( int iV = 0; iV < views.count(); ++iV ) {
112         if ( SMESH_Actor* actor = FindActorByEntry( views[iV], theEntry)) {
113           if(SVTK_ViewWindow* vtkWnd = GetVtkViewWindow(views[iV]))
114             vtkWnd->RemoveActor(actor);
115           actor->Delete();
116         }
117       }
118       int aStudyId = aViewManager->study()->id();
119       TVisualObjCont::key_type aKey(aStudyId,theEntry);
120       TVisualObjCont::iterator anIter = VISUAL_OBJ_CONT.find(aKey);
121       if(anIter != VISUAL_OBJ_CONT.end()) {
122         // for unknown reason, object destructor is not called, so clear object manually
123         anIter->second->GetUnstructuredGrid()->SetCells(0,0,0);
124         anIter->second->GetUnstructuredGrid()->SetPoints(0);
125       }
126       VISUAL_OBJ_CONT.erase(aKey);
127     }
128   }
129   //================================================================================
130   /*!
131    * \brief Remove all VisualObjs and their actors from all views
132    */
133   //================================================================================
134
135   void RemoveAllObjectsWithActors()
136   {
137     SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>
138       ( SUIT_Session::session()->activeApplication() );
139     if (!app) return;
140     ViewManagerList viewMgrs = app->viewManagers();
141     for ( int iM = 0; iM < viewMgrs.count(); ++iM ) {
142       SUIT_ViewManager* aViewManager = viewMgrs.at( iM );
143       if ( aViewManager && aViewManager->getType() == SVTK_Viewer::Type()) {
144         QVector<SUIT_ViewWindow*> views = aViewManager->getViews();
145         for ( int iV = 0; iV < views.count(); ++iV ) {
146           if(SVTK_ViewWindow* vtkWnd = GetVtkViewWindow(views[iV])) {
147             vtkRenderer *aRenderer = vtkWnd->getRenderer();
148             VTK::ActorCollectionCopy aCopy(aRenderer->GetActors());
149             vtkActorCollection *actors = aCopy.GetActors();
150             for (int i = 0; i < actors->GetNumberOfItems(); ++i ) {
151               // size of actors changes inside the loop
152               if (SMESH_Actor *actor = dynamic_cast<SMESH_Actor*>(actors->GetItemAsObject(i)))
153               {
154                 vtkWnd->RemoveActor(actor);
155                 actor->Delete();
156               }
157             }
158           }
159         }
160       }
161     }
162     TVisualObjCont::iterator anIter = VISUAL_OBJ_CONT.begin();
163     for ( ; anIter != VISUAL_OBJ_CONT.end(); ++anIter ) {
164       // for unknown reason, object destructor is not called, so clear object manually
165       anIter->second->GetUnstructuredGrid()->SetCells(0,0,0);
166       anIter->second->GetUnstructuredGrid()->SetPoints(0);
167     }
168     VISUAL_OBJ_CONT.clear();
169   }
170
171   //================================================================================
172   /*!
173    * \brief Remove all VisualObjs of a study
174    */
175   //================================================================================
176
177   void RemoveVisuData(int studyID)
178   {
179     SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>
180       ( SUIT_Session::session()->activeApplication() );
181     if (!app) return;
182     ViewManagerList viewMgrs = app->viewManagers();
183     for ( int iM = 0; iM < viewMgrs.count(); ++iM ) {
184       SUIT_ViewManager* aViewManager = viewMgrs.at( iM );
185       if ( aViewManager && aViewManager->getType() == SVTK_Viewer::Type() &&
186            aViewManager->study()->id() == studyID ) {
187         QVector<SUIT_ViewWindow*> views = aViewManager->getViews();
188         for ( int iV = 0; iV < views.count(); ++iV ) {
189           if(SVTK_ViewWindow* vtkWnd = GetVtkViewWindow(views[iV])) {
190             vtkRenderer *aRenderer = vtkWnd->getRenderer();
191             VTK::ActorCollectionCopy aCopy(aRenderer->GetActors());
192             vtkActorCollection *actors = aCopy.GetActors();
193             for (int i = 0; i < actors->GetNumberOfItems(); ++i ) {
194               // size of actors changes inside the loop
195               if(SMESH_Actor *actor = dynamic_cast<SMESH_Actor*>(actors->GetItemAsObject(i)))
196               {
197                 vtkWnd->RemoveActor(actor);
198                 actor->Delete();
199               }
200             }
201           }
202         }
203       }
204     }
205     TVisualObjCont::iterator anIter = VISUAL_OBJ_CONT.begin();
206     for ( ; anIter != VISUAL_OBJ_CONT.end(); ++anIter ) {
207       int curId = anIter->first.first;
208       if ( curId == studyID ) {
209         // for unknown reason, object destructor is not called, so clear object manually
210         anIter->second->GetUnstructuredGrid()->SetCells(0,0,0);
211         anIter->second->GetUnstructuredGrid()->SetPoints(0);
212         VISUAL_OBJ_CONT.erase( anIter-- );  // dercement occures before erase()
213       }
214     }
215   }
216
217   //================================================================================
218   /*!
219    * \brief Notify the user on problems during visualization
220    */
221   //================================================================================
222
223   void OnVisuException()
224   {
225     try {
226 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
227       OCC_CATCH_SIGNALS;
228 #endif
229       // PAL16774 (Crash after display of many groups). Salome sometimes crashes just
230       // after or at showing this message, so we do an additional check of available memory
231 //       char* buf = new char[100*1024];
232 //       delete [] buf;
233       SUIT_MessageBox::warning(SMESHGUI::desktop(), QObject::tr("SMESH_WRN_WARNING"),
234                                QObject::tr("SMESH_VISU_PROBLEM"));
235     } catch (...) {
236       // no more memory at all: last resort
237       MESSAGE_BEGIN ( "SMESHGUI_VTKUtils::OnVisuException(), exception even at showing a message!!!" <<
238                       std::endl << "Try to remove all visual data..." );
239       if (theVISU_MemoryReserve) {
240         delete theVISU_MemoryReserve;
241         theVISU_MemoryReserve = 0;
242       }
243       RemoveAllObjectsWithActors();
244       SUIT_MessageBox::warning(SMESHGUI::desktop(), QObject::tr("SMESH_WRN_WARNING"),
245                                QObject::tr("SMESH_VISU_PROBLEM_CLEAR"));
246       MESSAGE_END ( "...done" );
247     }
248   }
249   //================================================================================
250   /*!
251    * \brief Returns an updated visual object
252    */
253   //================================================================================
254
255   TVisualObjPtr GetVisualObj(int theStudyId, const char* theEntry){
256     TVisualObjPtr aVisualObj;
257     TVisualObjCont::key_type aKey(theStudyId,theEntry);
258     try{
259 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
260       OCC_CATCH_SIGNALS;
261 #endif
262       TVisualObjCont::iterator anIter = VISUAL_OBJ_CONT.find(aKey);
263       if(anIter != VISUAL_OBJ_CONT.end()){
264         aVisualObj = anIter->second;
265       }else{
266         SalomeApp_Application* app =
267           dynamic_cast<SalomeApp_Application*>( SMESHGUI::activeStudy()->application() );
268         _PTR(Study) aStudy = SMESHGUI::activeStudy()->studyDS();
269         _PTR(SObject) aSObj = aStudy->FindObjectID(theEntry);
270         if(aSObj){
271           _PTR(GenericAttribute) anAttr;
272           if(aSObj->FindAttribute(anAttr,"AttributeIOR")){
273             _PTR(AttributeIOR) anIOR = anAttr;
274             CORBA::String_var aVal = anIOR->Value().c_str();
275             CORBA::Object_var anObj = app->orb()->string_to_object( aVal.in() );
276             if(!CORBA::is_nil(anObj)){
277               //Try narrow to SMESH_Mesh interface
278               SMESH::SMESH_Mesh_var aMesh = SMESH::SMESH_Mesh::_narrow(anObj);
279               if(!aMesh->_is_nil()){
280                 aVisualObj.reset(new SMESH_MeshObj(aMesh));
281                 TVisualObjCont::value_type aValue(aKey,aVisualObj);
282                 VISUAL_OBJ_CONT.insert(aValue);
283               }
284               //Try narrow to SMESH_Group interface
285               SMESH::SMESH_GroupBase_var aGroup = SMESH::SMESH_GroupBase::_narrow(anObj);
286               if(!aGroup->_is_nil()){
287                 _PTR(SObject) aFatherSObj = aSObj->GetFather();
288                 if(!aFatherSObj) return aVisualObj;
289                 aFatherSObj = aFatherSObj->GetFather();
290                 if(!aFatherSObj) return aVisualObj;
291                 CORBA::String_var anEntry = aFatherSObj->GetID().c_str();
292                 TVisualObjPtr aVisObj = GetVisualObj(theStudyId,anEntry.in());
293                 if(SMESH_MeshObj* aMeshObj = dynamic_cast<SMESH_MeshObj*>(aVisObj.get())){
294                   aVisualObj.reset(new SMESH_GroupObj(aGroup,aMeshObj));
295                   TVisualObjCont::value_type aValue(aKey,aVisualObj);
296                   VISUAL_OBJ_CONT.insert(aValue);
297                 }
298               }
299               //Try narrow to SMESH_subMesh interface
300               SMESH::SMESH_subMesh_var aSubMesh = SMESH::SMESH_subMesh::_narrow(anObj);
301               if(!aSubMesh->_is_nil()){
302                 _PTR(SObject) aFatherSObj = aSObj->GetFather();
303                 if(!aFatherSObj) return aVisualObj;
304                 aFatherSObj = aFatherSObj->GetFather();
305                 if(!aFatherSObj) return aVisualObj;
306                 CORBA::String_var anEntry = aFatherSObj->GetID().c_str();
307                 TVisualObjPtr aVisObj = GetVisualObj(theStudyId,anEntry.in());
308                 if(SMESH_MeshObj* aMeshObj = dynamic_cast<SMESH_MeshObj*>(aVisObj.get())){
309                   aVisualObj.reset(new SMESH_subMeshObj(aSubMesh,aMeshObj));
310                   TVisualObjCont::value_type aValue(aKey,aVisualObj);
311                   VISUAL_OBJ_CONT.insert(aValue);
312                 }
313               }
314             }
315           }
316         }
317       }
318     }catch(...){
319       INFOS("GetMeshObj - There is no SMESH_Mesh object for the SALOMEDS::Strudy and Entry!!!");
320       return TVisualObjPtr();
321     }
322     // Update object
323     bool objModified = false;
324     if ( aVisualObj ) {
325       try {
326 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
327         OCC_CATCH_SIGNALS;
328 #endif
329         objModified = aVisualObj->Update();
330       }
331       catch (...) {
332 #ifdef _DEBUG_
333         MESSAGE ( "Exception in SMESHGUI_VTKUtils::GetVisualObj()" );
334 #endif
335         RemoveVisualObjectWithActors( theEntry ); // remove this object
336         OnVisuException();
337         aVisualObj.reset();
338       }
339     }
340
341     if ( objModified ) {
342       // PAL16631. Mesurements showed that to show aVisualObj in SHADING(default) mode,
343       // ~10 times more memory is used than it occupies.
344       // Warn the user if there is less free memory than 30 sizes of a grid
345       // TODO: estimate memory usage in other modes and take current mode into account
346       int freeMB = SMDS_Mesh::CheckMemory(true);
347       int usedMB = aVisualObj->GetUnstructuredGrid()->GetActualMemorySize() / 1024;
348       if ( freeMB > 0 && usedMB * 30 > freeMB ) {
349 #ifdef _DEBUG_
350         MESSAGE ( "SMESHGUI_VTKUtils::GetVisualObj(), freeMB=" << freeMB
351                << ", usedMB=" << usedMB );
352 #endif
353         bool continu = false;
354         if ( usedMB * 10 > freeMB )
355           // even dont try to show
356           SUIT_MessageBox::warning(SMESHGUI::desktop(), QObject::tr("SMESH_WRN_WARNING"),
357                                    QObject::tr("SMESH_NO_MESH_VISUALIZATION"));
358         else
359           // there is a chance to succeed
360           continu = SUIT_MessageBox::warning
361             (SMESHGUI::desktop(),
362              QObject::tr("SMESH_WRN_WARNING"),
363              QObject::tr("SMESH_CONTINUE_MESH_VISUALIZATION"),
364              SUIT_MessageBox::Yes | SUIT_MessageBox::No, 
365              SUIT_MessageBox::Yes ) == SUIT_MessageBox::Yes;
366         if ( !continu ) {
367           // remove the corresponding actors from all views
368           RemoveVisualObjectWithActors( theEntry );
369           aVisualObj.reset();
370         }
371       }
372     }
373
374     return aVisualObj;
375   }
376
377
378   /*! Return active view window, if it instantiates SVTK_ViewWindow class,
379    *  overwise find or create corresponding view window, make it active and return it.
380    *  \note Active VVTK_ViewWindow can be returned, because it inherits SVTK_ViewWindow.
381    */
382   SVTK_ViewWindow* GetViewWindow (const SalomeApp_Module* theModule,
383                                   bool createIfNotFound)
384   {
385     SalomeApp_Application* anApp;
386     if (theModule)
387       anApp = theModule->getApp();
388     else
389       anApp = dynamic_cast<SalomeApp_Application*>
390         (SUIT_Session::session()->activeApplication());
391
392     if (anApp) {
393       if (SVTK_ViewWindow* aView = dynamic_cast<SVTK_ViewWindow*>(anApp->desktop()->activeWindow()))
394         return aView;
395
396       SUIT_ViewManager* aViewManager =
397         anApp->getViewManager(SVTK_Viewer::Type(), createIfNotFound);
398       if (aViewManager) {
399         if (SUIT_ViewWindow* aViewWindow = aViewManager->getActiveView()) {
400           if (SVTK_ViewWindow* aView = dynamic_cast<SVTK_ViewWindow*>(aViewWindow)) {
401             aViewWindow->raise();
402             aViewWindow->setFocus();
403             return aView;
404           }
405         }
406       }
407     }
408     return NULL;
409   }
410
411   SVTK_ViewWindow* FindVtkViewWindow (SUIT_ViewManager* theMgr,
412                                       SUIT_ViewWindow * theWindow)
413   {
414     if( !theMgr )
415       return NULL;
416
417     QVector<SUIT_ViewWindow*> views = theMgr->getViews();
418     if( views.contains( theWindow ) )
419       return GetVtkViewWindow( theWindow );
420     else
421       return NULL;
422   }
423
424   SVTK_ViewWindow* GetVtkViewWindow(SUIT_ViewWindow* theWindow){
425     return dynamic_cast<SVTK_ViewWindow*>(theWindow);
426   }
427
428 /*  SUIT_ViewWindow* GetActiveWindow()
429   {
430     SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>( SUIT_Session::session()->activeApplication() );
431     if( !app )
432       return NULL;
433     SUIT_ViewManager* mgr = app->activeViewManager();
434     if( mgr )
435       return mgr->getActiveView();
436     else
437       return NULL;
438   }*/
439
440   SVTK_ViewWindow* GetCurrentVtkView(){
441     return GetVtkViewWindow( GetActiveWindow() );
442   }
443
444
445   void RepaintCurrentView()
446   {
447     if (SVTK_ViewWindow* wnd = GetCurrentVtkView())
448     {
449       try {
450 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
451         OCC_CATCH_SIGNALS;
452 #endif
453         wnd->getRenderer()->Render();
454         wnd->Repaint(false);
455       }
456       catch (...) {
457 #ifdef _DEBUG_
458         MESSAGE ( "Exception in SMESHGUI_VTKUtils::RepaintCurrentView()" );
459 #endif
460         OnVisuException();
461       }
462     }
463   }
464
465   void RepaintViewWindow(SVTK_ViewWindow* theWindow)
466   {
467     try {
468 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
469       OCC_CATCH_SIGNALS;
470 #endif
471       theWindow->getRenderer()->Render();
472       theWindow->Repaint();
473     }
474     catch (...) {
475 #ifdef _DEBUG_
476       MESSAGE ( "Exception in SMESHGUI_VTKUtils::RepaintViewWindow(SVTK_ViewWindow*)" );
477 #endif
478       OnVisuException();
479     }
480   }
481
482   void RenderViewWindow(SVTK_ViewWindow* theWindow)
483   {
484     try {
485 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
486       OCC_CATCH_SIGNALS;
487 #endif
488       theWindow->getRenderer()->Render();
489       theWindow->Repaint();
490     }
491     catch (...) {
492 #ifdef _DEBUG_
493       MESSAGE ( "Exception in SMESHGUI_VTKUtils::RenderViewWindow(SVTK_ViewWindow*)" );
494 #endif
495       OnVisuException();
496     }
497   }
498
499   void FitAll(){
500     if(SVTK_ViewWindow* wnd = GetCurrentVtkView() ){
501       try {
502 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
503         OCC_CATCH_SIGNALS;
504 #endif
505         wnd->onFitAll();
506         wnd->Repaint();
507       }
508       catch (...) {
509 #ifdef _DEBUG_
510         MESSAGE ( "Exception in SMESHGUI_VTKUtils::FitAll()" );
511 #endif
512         OnVisuException();
513       }
514     }
515   }
516
517
518   SMESH_Actor* FindActorByEntry(SUIT_ViewWindow *theWindow,
519                                 const char* theEntry)
520   {
521     if(SVTK_ViewWindow* aViewWindow = GetVtkViewWindow(theWindow)){
522       vtkRenderer *aRenderer = aViewWindow->getRenderer();
523       VTK::ActorCollectionCopy aCopy(aRenderer->GetActors());
524       vtkActorCollection *aCollection = aCopy.GetActors();
525       aCollection->InitTraversal();
526       while(vtkActor *anAct = aCollection->GetNextActor()){
527         if(SMESH_Actor *anActor = dynamic_cast<SMESH_Actor*>(anAct)){
528           if(anActor->hasIO()){
529             Handle(SALOME_InteractiveObject) anIO = anActor->getIO();
530             if(anIO->hasEntry() && strcmp(anIO->getEntry(),theEntry) == 0){
531               return anActor;
532             }
533           }
534         }
535       }
536     }
537     return NULL;
538   }
539
540
541   SMESH_Actor* FindActorByEntry(const char* theEntry){
542     return FindActorByEntry(GetActiveWindow(),theEntry);
543   }
544
545
546   SMESH_Actor* FindActorByObject(CORBA::Object_ptr theObject){
547     SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>( SUIT_Session::session()->activeApplication() );
548     if( !app )
549       return NULL;
550
551     if(!CORBA::is_nil(theObject)){
552       _PTR(Study) aStudy = GetActiveStudyDocument();
553       CORBA::String_var anIOR = app->orb()->object_to_string( theObject );
554       _PTR(SObject) aSObject = aStudy->FindObjectIOR(anIOR.in());
555       if(aSObject){
556         CORBA::String_var anEntry = aSObject->GetID().c_str();
557         return FindActorByEntry(anEntry.in());
558       }
559     }
560     return NULL;
561   }
562
563
564   SMESH_Actor* CreateActor(_PTR(Study) theStudy,
565                            const char* theEntry,
566                            int theIsClear)
567   {
568     SMESH_Actor *anActor = NULL;
569     CORBA::Long anId = theStudy->StudyId();
570     if(TVisualObjPtr aVisualObj = GetVisualObj(anId,theEntry)){
571       _PTR(SObject) aSObj = theStudy->FindObjectID(theEntry);
572       if(aSObj){
573         _PTR(GenericAttribute) anAttr;
574         if(aSObj->FindAttribute(anAttr,"AttributeName")){
575           _PTR(AttributeName) aName = anAttr;
576           std::string aNameVal = aName->Value();
577           anActor = SMESH_Actor::New(aVisualObj,theEntry,aNameVal.c_str(),theIsClear);
578         }
579
580         SMESH::SMESH_GroupBase_var aGroup = SMESH::SMESH_GroupBase::_narrow( SMESH::SObjectToObject( aSObj ));
581         if(!CORBA::is_nil(aGroup))
582         {
583           SALOMEDS::Color aColor = aGroup->GetColor();
584           if( !( aColor.R > 0 || aColor.G > 0 || aColor.B > 0 ) )
585           {
586             int r = 0, g = 0, b = 0;
587             SMESH::GetColor( "SMESH", "fill_color", r, g, b, QColor( 0, 170, 255 ) );
588             aColor.R = (float)r / 255.0;
589             aColor.G = (float)g / 255.0;
590             aColor.B = (float)b / 255.0;
591             aGroup->SetColor( aColor );
592           }
593           if( aGroup->GetType() == SMESH::NODE )
594             anActor->SetNodeColor( aColor.R, aColor.G, aColor.B );
595           else if( aGroup->GetType() == SMESH::EDGE )
596             anActor->SetEdgeColor( aColor.R, aColor.G, aColor.B );
597           else if( aGroup->GetType() == SMESH::ELEM0D )
598             anActor->Set0DColor( aColor.R, aColor.G, aColor.B );
599           else
600             anActor->SetSufaceColor( aColor.R, aColor.G, aColor.B );
601         }
602       }
603     }
604     return anActor;
605   }
606
607
608   void DisplayActor( SUIT_ViewWindow *theWnd, SMESH_Actor* theActor){
609     if(SVTK_ViewWindow* vtkWnd = GetVtkViewWindow(theWnd)){
610       try {
611 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
612         OCC_CATCH_SIGNALS;
613 #endif
614         vtkWnd->AddActor(theActor);
615         vtkWnd->Repaint();
616       }
617       catch (...) {
618 #ifdef _DEBUG_
619         MESSAGE ( "Exception in SMESHGUI_VTKUtils::DisplayActor()" );
620 #endif
621         OnVisuException();
622       }
623     }
624   }
625
626
627   void RemoveActor( SUIT_ViewWindow *theWnd, SMESH_Actor* theActor){
628     if(SVTK_ViewWindow* vtkWnd = GetVtkViewWindow(theWnd)){
629       vtkWnd->RemoveActor(theActor);
630       if(theActor->hasIO()){
631         Handle(SALOME_InteractiveObject) anIO = theActor->getIO();
632         if(anIO->hasEntry()){
633           std::string anEntry = anIO->getEntry();
634           SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>( vtkWnd->getViewManager()->study() );
635           int aStudyId = aStudy->id();
636           TVisualObjCont::key_type aKey(aStudyId,anEntry);
637           VISUAL_OBJ_CONT.erase(aKey);
638         }
639       }
640       theActor->Delete();
641       vtkWnd->Repaint();
642     }
643   }
644
645   //================================================================================
646   /*!
647    * \brief Return true if there are no SMESH actors in a view
648    */
649   //================================================================================
650
651   bool noSmeshActors(SUIT_ViewWindow *theWnd)
652   {
653     if(SVTK_ViewWindow* aViewWindow = GetVtkViewWindow(theWnd)) {
654       vtkRenderer *aRenderer = aViewWindow->getRenderer();
655       VTK::ActorCollectionCopy aCopy(aRenderer->GetActors());
656       vtkActorCollection *aCollection = aCopy.GetActors();
657       aCollection->InitTraversal();
658       while(vtkActor *anAct = aCollection->GetNextActor())
659         if(dynamic_cast<SMESH_Actor*>(anAct))
660           return false;
661     }
662     return true;
663   }
664
665   bool UpdateView(SUIT_ViewWindow *theWnd, EDisplaing theAction, const char* theEntry)
666   {
667     bool OK = false;
668     SVTK_ViewWindow* aViewWnd = GetVtkViewWindow(theWnd);
669     if (!aViewWnd)
670       return OK;
671
672     {
673       OK = true;
674       vtkRenderer *aRenderer = aViewWnd->getRenderer();
675       VTK::ActorCollectionCopy aCopy(aRenderer->GetActors());
676       vtkActorCollection *aCollection = aCopy.GetActors();
677       aCollection->InitTraversal();
678
679       switch (theAction) {
680       case eDisplayAll: {
681         while (vtkActor *anAct = aCollection->GetNextActor()) {
682           if (SMESH_Actor *anActor = dynamic_cast<SMESH_Actor*>(anAct)) {
683             anActor->SetVisibility(true);
684           }
685         }
686         break;
687       }
688       case eDisplayOnly:
689       case eEraseAll: {
690         while (vtkActor *anAct = aCollection->GetNextActor()) {
691           if (SMESH_Actor *anActor = dynamic_cast<SMESH_Actor*>(anAct)) {
692             anActor->SetVisibility(false);
693           }
694         }
695       }
696       default: {
697         if (SMESH_Actor *anActor = FindActorByEntry(theWnd,theEntry)) {
698           switch (theAction) {
699             case eDisplay:
700             case eDisplayOnly:
701               anActor->SetVisibility(true);
702               if (theAction == eDisplayOnly) aRenderer->ResetCameraClippingRange();
703               break;
704             case eErase:
705               anActor->SetVisibility(false);
706               break;
707           }
708         } else {
709           switch (theAction) {
710           case eDisplay:
711           case eDisplayOnly:
712             {
713               SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>(theWnd->getViewManager()->study());
714               _PTR(Study) aDocument = aStudy->studyDS();
715               // Pass non-visual objects (hypotheses, etc.), return true in this case
716               CORBA::Long anId = aDocument->StudyId();
717               TVisualObjPtr aVisualObj;
718               if ( (aVisualObj = GetVisualObj(anId,theEntry)) && aVisualObj->IsValid())
719               {
720                 if ((anActor = CreateActor(aDocument,theEntry,true))) {
721                   bool needFitAll = noSmeshActors(theWnd); // fit for the first object only
722                   DisplayActor(theWnd,anActor);
723                   // FitAll(); - PAL16770(Display of a group performs an automatic fit all)
724                   if (needFitAll) FitAll();
725                 } else {
726                   OK = false;
727                 }
728               }
729               break;
730             }
731           }
732         }
733       }
734       }
735     }
736     return OK;
737   }
738
739
740   bool UpdateView(EDisplaing theAction, const char* theEntry){
741     SalomeApp_Study* aStudy = dynamic_cast< SalomeApp_Study* >( GetActiveStudy() );
742     SalomeApp_Application* app = dynamic_cast< SalomeApp_Application* >( aStudy->application() );
743     SUIT_ViewWindow *aWnd = app->activeViewManager()->getActiveView();
744     return UpdateView(aWnd,theAction,theEntry);
745   }
746
747   void UpdateView(){
748     if(SVTK_ViewWindow* aWnd = SMESH::GetCurrentVtkView()){
749       LightApp_SelectionMgr* mgr = SMESHGUI::selectionMgr();
750       SALOME_ListIO selected; mgr->selectedObjects( selected );
751
752       if( selected.Extent() == 0){
753         vtkRenderer* aRenderer = aWnd->getRenderer();
754         VTK::ActorCollectionCopy aCopy(aRenderer->GetActors());
755         vtkActorCollection *aCollection = aCopy.GetActors();
756         aCollection->InitTraversal();
757         while(vtkActor *anAct = aCollection->GetNextActor()){
758           if(SMESH_Actor *anActor = dynamic_cast<SMESH_Actor*>(anAct)){
759             if(anActor->hasIO())
760               if (!Update(anActor->getIO(),anActor->GetVisibility()))
761                 break; // avoid multiple warinings if visu failed
762           }
763         }
764       }else{
765         SALOME_ListIteratorOfListIO anIter( selected );
766         for( ; anIter.More(); anIter.Next()){
767           Handle(SALOME_InteractiveObject) anIO = anIter.Value();
768           if ( !Update(anIO,true) )
769             break; // avoid multiple warinings if visu failed
770         }
771       }
772       RepaintCurrentView();
773     }
774   }
775
776
777   bool Update(const Handle(SALOME_InteractiveObject)& theIO, bool theDisplay)
778   {
779     _PTR(Study) aStudy = GetActiveStudyDocument();
780     CORBA::Long anId = aStudy->StudyId();
781     if ( TVisualObjPtr aVisualObj = SMESH::GetVisualObj(anId,theIO->getEntry())) {
782       if ( theDisplay )
783         UpdateView(SMESH::eDisplay,theIO->getEntry());
784       return true;
785     }
786     return false;
787   }
788
789
790   void UpdateSelectionProp( SMESHGUI* theModule ) {
791     if( !theModule )
792       return;
793
794     SalomeApp_Application* app = dynamic_cast< SalomeApp_Application* >( theModule->application() );
795     if( !app )
796     {
797       MESSAGE( "UpdateSelectionProp: Application is null" );
798       return;
799     }
800
801     SUIT_ViewManager* vm = app->activeViewManager();
802     if( !vm )
803     {
804       MESSAGE( "UpdateSelectionProp: View manager is null" );
805       return;
806     }
807
808     QVector<SUIT_ViewWindow*> views = vm->getViews();
809
810     SUIT_ResourceMgr* mgr = SMESH::GetResourceMgr( theModule );
811     if( !mgr )
812     {
813       MESSAGE( "UpdateSelectionProp: Resource manager is null" );
814       return;
815     }
816
817     QColor aHiColor = mgr->colorValue( "SMESH", "selection_object_color", Qt::white ),
818            aSelColor = mgr->colorValue( "SMESH", "selection_element_color", Qt::yellow ),
819            aPreColor = mgr->colorValue( "SMESH", "highlight_color", Qt::cyan );
820
821     int SW = mgr->integerValue( "SMESH", "selection_width", 5 ),
822         PW = mgr->integerValue( "SMESH", "highlight_width", 5 );
823
824     // adjust highlight_width to the width of mesh entities
825     int aPointSize  = mgr->integerValue("SMESH", "node_size", 3);
826     int aElem0DSize = mgr->integerValue("SMESH", "elem0d_size", 5);
827     int aLineWidth  = mgr->integerValue("SMESH", "element_width", 1);
828     int maxSize = aPointSize;
829     if (aElem0DSize > maxSize) maxSize = aElem0DSize;
830     if (aLineWidth > maxSize) maxSize = aLineWidth;
831     if (PW < maxSize + 2) PW = maxSize + 2;
832
833     double SP1 = mgr->doubleValue( "SMESH", "selection_precision_node", 0.025 ),
834            SP2 = mgr->doubleValue( "SMESH", "selection_precision_element", 0.001 ),
835            SP3 = mgr->doubleValue( "SMESH", "selection_precision_object", 0.025 );
836
837     for ( int i=0, n=views.count(); i<n; i++ ){
838       // update VTK viewer properties
839       if(SVTK_ViewWindow* aVtkView = GetVtkViewWindow( views[i] )){
840         // mesh element selection
841         aVtkView->SetSelectionProp(aSelColor.red()/255.,
842                                    aSelColor.green()/255.,
843                                    aSelColor.blue()/255.,
844                                    SW );
845         // tolerances
846         aVtkView->SetSelectionTolerance(SP1, SP2, SP3);
847
848         // pre-selection
849         aVtkView->SetPreselectionProp(aPreColor.red()/255.,
850                                       aPreColor.green()/255.,
851                                       aPreColor.blue()/255.,
852                                       PW);
853         // update actors
854         vtkRenderer* aRenderer = aVtkView->getRenderer();
855         VTK::ActorCollectionCopy aCopy(aRenderer->GetActors());
856         vtkActorCollection *aCollection = aCopy.GetActors();
857         aCollection->InitTraversal();
858         while(vtkActor *anAct = aCollection->GetNextActor()){
859           if(SMESH_Actor *anActor = dynamic_cast<SMESH_Actor*>(anAct)){
860             anActor->SetHighlightColor(aHiColor.red()/255.,
861                                        aHiColor.green()/255.,
862                                        aHiColor.blue()/255.);
863             anActor->SetPreHighlightColor(aPreColor.red()/255.,
864                                           aPreColor.green()/255.,
865                                           aPreColor.blue()/255.);
866           }
867         }
868       }
869     }
870   }
871
872
873   //----------------------------------------------------------------------------
874   SVTK_Selector*
875   GetSelector(SUIT_ViewWindow *theWindow)
876   {
877     if(SVTK_ViewWindow* aWnd = GetVtkViewWindow(theWindow))
878       return aWnd->GetSelector();
879
880     return NULL;
881   }
882
883   void SetFilter(const Handle(VTKViewer_Filter)& theFilter,
884                  SVTK_Selector* theSelector)
885   {
886     if (theSelector)
887       theSelector->SetFilter(theFilter);
888   }
889
890   Handle(VTKViewer_Filter) GetFilter(int theId, SVTK_Selector* theSelector)
891   {
892     return theSelector->GetFilter(theId);
893   }
894
895   bool IsFilterPresent(int theId, SVTK_Selector* theSelector)
896   {
897     return theSelector->IsFilterPresent(theId);
898   }
899
900   void RemoveFilter(int theId, SVTK_Selector* theSelector)
901   {
902     theSelector->RemoveFilter(theId);
903   }
904
905   void RemoveFilters(SVTK_Selector* theSelector)
906   {
907     for ( int id = SMESH::NodeFilter; theSelector && id < SMESH::LastFilter; id++ )
908       theSelector->RemoveFilter( id );
909   }
910
911   bool IsValid(SALOME_Actor* theActor, int theCellId,
912                SVTK_Selector* theSelector)
913   {
914     return theSelector->IsValid(theActor,theCellId);
915   }
916
917
918   //----------------------------------------------------------------------------
919   void SetPointRepresentation(bool theIsVisible){
920     if(SVTK_ViewWindow* aViewWindow = GetCurrentVtkView()){
921       vtkRenderer *aRenderer = aViewWindow->getRenderer();
922       VTK::ActorCollectionCopy aCopy(aRenderer->GetActors());
923       vtkActorCollection *aCollection = aCopy.GetActors();
924       aCollection->InitTraversal();
925       while(vtkActor *anAct = aCollection->GetNextActor()){
926         if(SMESH_Actor *anActor = dynamic_cast<SMESH_Actor*>(anAct)){
927           if(anActor->GetVisibility()){
928             anActor->SetPointRepresentation(theIsVisible);
929           }
930         }
931       }
932       RepaintCurrentView();
933     }
934   }
935
936
937   void SetPickable(SMESH_Actor* theActor){
938     if(SVTK_ViewWindow* aWnd = GetCurrentVtkView()){
939       int anIsAllPickable = (theActor == NULL);
940       vtkRenderer *aRenderer = aWnd->getRenderer();
941       VTK::ActorCollectionCopy aCopy(aRenderer->GetActors());
942       vtkActorCollection *aCollection = aCopy.GetActors();
943       aCollection->InitTraversal();
944       while(vtkActor *anAct = aCollection->GetNextActor()){
945         if(SALOME_Actor *anActor = dynamic_cast<SALOME_Actor*>(anAct)){
946           if(anActor->GetVisibility()){
947             anActor->SetPickable(anIsAllPickable);
948           }
949         }
950       }
951       if(theActor)
952         theActor->SetPickable(!anIsAllPickable);
953       RepaintCurrentView();
954     }
955   }
956
957
958   //----------------------------------------------------------------------------
959   int GetNameOfSelectedNodes(SVTK_Selector* theSelector,
960                              const Handle(SALOME_InteractiveObject)& theIO,
961                              QString& theName)
962   {
963     theName = "";
964     TColStd_IndexedMapOfInteger aMapIndex;
965     theSelector->GetIndex(theIO,aMapIndex);
966
967     for(int i = 1; i <= aMapIndex.Extent(); i++)
968       theName += QString(" %1").arg(aMapIndex(i));
969
970     return aMapIndex.Extent();
971   }
972
973   int GetNameOfSelectedElements(SVTK_Selector* theSelector,
974                                 const Handle(SALOME_InteractiveObject)& theIO,
975                                 QString& theName)
976   {
977     theName = "";
978     TColStd_IndexedMapOfInteger aMapIndex;
979     theSelector->GetIndex(theIO,aMapIndex);
980
981     typedef std::set<int> TIdContainer;
982     TIdContainer anIdContainer;
983     for( int i = 1; i <= aMapIndex.Extent(); i++)
984       anIdContainer.insert(aMapIndex(i));
985
986     TIdContainer::const_iterator anIter = anIdContainer.begin();
987     for( ; anIter != anIdContainer.end(); anIter++)
988       theName += QString(" %1").arg(*anIter);
989
990     return aMapIndex.Extent();
991   }
992
993
994   int GetEdgeNodes(SVTK_Selector* theSelector,
995                    const TVisualObjPtr& theVisualObject,
996                    int& theId1,
997                    int& theId2)
998   {
999     const SALOME_ListIO& selected = theSelector->StoredIObjects();
1000
1001     if ( selected.Extent() != 1 )
1002       return -1;
1003
1004     Handle(SALOME_InteractiveObject) anIO = selected.First();
1005     if ( anIO.IsNull() || !anIO->hasEntry() )
1006       return -1;
1007
1008     TColStd_IndexedMapOfInteger aMapIndex;
1009     theSelector->GetIndex( anIO, aMapIndex );
1010     if ( aMapIndex.Extent() != 2 )
1011       return -1;
1012
1013     int anObjId = -1, anEdgeNum = -1;
1014     for ( int i = 1; i <= aMapIndex.Extent(); i++ ) {
1015       int aVal = aMapIndex( i );
1016       if ( aVal > 0 )
1017         anObjId = aVal;
1018       else
1019         anEdgeNum = abs( aVal ) - 1;
1020     }
1021
1022     if ( anObjId == -1 || anEdgeNum == -1 )
1023       return -1;
1024
1025     return theVisualObject->GetEdgeNodes( anObjId, anEdgeNum, theId1, theId2 ) ? 1 : -1;
1026   }
1027
1028   //----------------------------------------------------------------------------
1029   int GetNameOfSelectedNodes(LightApp_SelectionMgr *theMgr,
1030                              const Handle(SALOME_InteractiveObject)& theIO,
1031                              QString& theName)
1032   {
1033     theName = "";
1034     if(theIO->hasEntry()){
1035       if(FindActorByEntry(theIO->getEntry())){
1036         TColStd_IndexedMapOfInteger aMapIndex;
1037         theMgr->GetIndexes(theIO,aMapIndex);
1038         for(int i = 1; i <= aMapIndex.Extent(); i++){
1039           theName += QString(" %1").arg(aMapIndex(i));
1040         }
1041         return aMapIndex.Extent();
1042       }
1043     }
1044     return -1;
1045   }
1046
1047   int GetNameOfSelectedNodes(LightApp_SelectionMgr *theMgr, QString& theName){
1048     theName = "";
1049     SALOME_ListIO selected; theMgr->selectedObjects( selected );
1050     if(selected.Extent() == 1){
1051       Handle(SALOME_InteractiveObject) anIO = selected.First();
1052       return GetNameOfSelectedNodes(theMgr,anIO,theName);
1053     }
1054     return -1;
1055   }
1056
1057
1058   int GetNameOfSelectedElements(LightApp_SelectionMgr *theMgr,
1059                                 const Handle(SALOME_InteractiveObject)& theIO,
1060                                 QString& theName)
1061   {
1062     theName = "";
1063     if(theIO->hasEntry()){
1064       if(FindActorByEntry(theIO->getEntry())){
1065         TColStd_IndexedMapOfInteger aMapIndex;
1066         theMgr->GetIndexes(theIO,aMapIndex);
1067         typedef std::set<int> TIdContainer;
1068         TIdContainer anIdContainer;
1069         for( int i = 1; i <= aMapIndex.Extent(); i++)
1070           anIdContainer.insert(aMapIndex(i));
1071         TIdContainer::const_iterator anIter = anIdContainer.begin();
1072         for( ; anIter != anIdContainer.end(); anIter++){
1073           theName += QString(" %1").arg(*anIter);
1074         }
1075         return aMapIndex.Extent();
1076       }
1077     }
1078     return -1;
1079   }
1080
1081
1082   int GetNameOfSelectedElements(LightApp_SelectionMgr *theMgr, QString& theName)
1083   {
1084     theName = "";
1085     SALOME_ListIO selected; theMgr->selectedObjects( selected );
1086
1087     if( selected.Extent() == 1){
1088       Handle(SALOME_InteractiveObject) anIO = selected.First();
1089       return GetNameOfSelectedElements(theMgr,anIO,theName);
1090     }
1091     return -1;
1092   }
1093
1094   int GetSelected(LightApp_SelectionMgr*       theMgr,
1095                   TColStd_IndexedMapOfInteger& theMap,
1096                   const bool                   theIsElement)
1097   {
1098     theMap.Clear();
1099     SALOME_ListIO selected; theMgr->selectedObjects( selected );
1100
1101     if ( selected.Extent() == 1 )
1102     {
1103       Handle(SALOME_InteractiveObject) anIO = selected.First();
1104       if ( anIO->hasEntry() ) {
1105         theMgr->GetIndexes( anIO, theMap );
1106       }
1107     }
1108     return theMap.Extent();
1109   }
1110
1111
1112   int GetEdgeNodes( LightApp_SelectionMgr* theMgr, int& theId1, int& theId2 )
1113   {
1114     SALOME_ListIO selected; theMgr->selectedObjects( selected );
1115
1116     if ( selected.Extent() != 1 )
1117       return -1;
1118
1119     Handle(SALOME_InteractiveObject) anIO = selected.First();
1120     if ( anIO.IsNull() || !anIO->hasEntry() )
1121       return -1;
1122
1123     SMESH_Actor *anActor = SMESH::FindActorByEntry( anIO->getEntry() );
1124     if ( anActor == 0 )
1125       return -1;
1126
1127     TColStd_IndexedMapOfInteger aMapIndex;
1128     theMgr->GetIndexes( anIO, aMapIndex );
1129     if ( aMapIndex.Extent() != 2 )
1130       return -1;
1131
1132     int anObjId = -1, anEdgeNum = -1;
1133     for ( int i = 1; i <= aMapIndex.Extent(); i++ ) {
1134       int aVal = aMapIndex( i );
1135       if ( aVal > 0 )
1136         anObjId = aVal;
1137       else
1138         anEdgeNum = abs( aVal );
1139     }
1140
1141     if ( anObjId == -1 || anEdgeNum == -1 )
1142       return -1;
1143
1144     return anActor->GetObject()->GetEdgeNodes( anObjId, anEdgeNum, theId1, theId2 ) ? 1 : -1;
1145   }
1146
1147   void SetControlsPrecision( const long theVal )
1148   {
1149     if( SVTK_ViewWindow* aWnd = SMESH::GetCurrentVtkView() )
1150     {
1151       vtkRenderer *aRenderer = aWnd->getRenderer();
1152       VTK::ActorCollectionCopy aCopy(aRenderer->GetActors());
1153       vtkActorCollection *aCollection = aCopy.GetActors();
1154       aCollection->InitTraversal();
1155
1156       while ( vtkActor *anAct = aCollection->GetNextActor())
1157       {
1158         if ( SMESH_Actor *anActor = dynamic_cast<SMESH_Actor*>( anAct ) )
1159         {
1160           anActor->SetControlsPrecision( theVal );
1161           anActor->SetControlMode( anActor->GetControlMode() );
1162         }
1163       }
1164
1165     }
1166   }
1167 } // end of namespace SMESH