Salome HOME
6bbf7d15eccf6548685e32f6633b1fe01fedeac1
[modules/gui.git] / src / SVTK / SVTK_Selector.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 //  SALOME SALOMEGUI : implementation of desktop and GUI kernel
23 //  File   : SALOME_Selection.cxx
24 //  Author : Nicolas REJNERI
25 //  Module : SALOME
26 //  $Header$
27 //
28 #include "SVTK_SelectorDef.h"
29
30 #include <VTKViewer_Filter.h>
31
32 #include "SALOME_Actor.h"
33
34 #include <SUIT_Session.h>
35 #include <SUIT_ResourceMgr.h>
36
37 #include <TColStd_MapIteratorOfMapOfInteger.hxx>
38 #include <TColStd_IndexedMapOfInteger.hxx>
39
40 #include <vtkCallbackCommand.h>
41 #include <vtkActorCollection.h>
42 #include <vtkCellPicker.h>
43
44
45 /*!
46   Find first SALOME_Actor from the end of actors collection
47 */
48 inline
49 SALOME_Actor* 
50 GetLastSALOMEActor(vtkActorCollection* theCollection)
51 {
52   if (theCollection) {
53     for (int i = theCollection->GetNumberOfItems() - 1; i >= 0; i--) {
54       if (SALOME_Actor* anActor = dynamic_cast<SALOME_Actor*>(theCollection->GetItemAsObject(i)))
55         if (anActor->hasIO())
56           return anActor;
57     }
58   }
59   return NULL;
60 }
61
62
63 /*!
64   \return new SVTK_Selector
65 */
66 SVTK_Selector* 
67 SVTK_Selector
68 ::New()
69 {
70   return new SVTK_SelectorDef();
71 }
72
73 /*!
74   Default constructor
75 */
76 SVTK_SelectorDef
77 ::SVTK_SelectorDef():
78   myPicker(vtkPicker::New()),
79   myCellPicker(vtkCellPicker::New())
80 {
81   mySelectionMode = ActorSelection;
82
83   myPicker->Delete();
84   myCellPicker->Delete();
85 }
86
87 /*!
88   Destructor
89 */
90 SVTK_SelectorDef
91 ::~SVTK_SelectorDef()
92 {
93 }
94
95 /*!
96   To invoke selectionChanged signals
97 */
98 void 
99 SVTK_SelectorDef
100 ::StartPickCallback()
101 {
102   this->InvokeEvent(vtkCommand::StartPickEvent,NULL);
103 }
104
105 /*!
106   To invoke selectionChanged signals
107 */
108 void 
109 SVTK_SelectorDef
110 ::EndPickCallback()
111 {
112   this->InvokeEvent(vtkCommand::EndPickEvent,NULL);
113 }
114
115 /*!
116   To change current Selection_Mode (as outside effect, it invokes selectionChange signal)
117 */
118 void 
119 SVTK_SelectorDef
120 ::SetSelectionMode(Selection_Mode theMode)
121 {
122   if(mySelectionMode != theMode){
123     mySelectionMode = theMode;
124     myMapIOSubIndex.clear();
125     this->EndPickCallback();
126   }
127 }
128
129 /*!
130   Clear selection
131 */
132 void 
133 SVTK_SelectorDef
134 ::ClearIObjects() 
135 {
136   myIO2Actors.clear();
137   myIObjects.clear();
138   myMapIOSubIndex.clear();
139 }
140
141 /*!
142   \return true if the SALOME_InteractiveObject presents into selection
143 */
144 bool
145 SVTK_SelectorDef
146 ::IsSelected(const Handle(SALOME_InteractiveObject)& theIO) const
147 {
148   return !theIO.IsNull() && (myIObjects.find(theIO) != myIObjects.end());
149 }
150
151 /*!
152   \return true if the SALOME_Actor presents into selection
153 */
154 bool
155 SVTK_SelectorDef
156 ::IsSelected(SALOME_Actor* theActor) const
157 {
158   const Handle(SALOME_InteractiveObject) anIO = theActor->getIO();
159   return IsSelected(anIO) && myIO2Actors.find(anIO) != myIO2Actors.end();
160 }
161
162 /*!
163   \return corresponding SALOME_Actor for SALOME_InteractiveObject
164   \param theIO - SALOME_InteractiveObject
165 */
166 SALOME_Actor*
167 SVTK_SelectorDef
168 ::GetActor(const Handle(SALOME_InteractiveObject)& theIO) const
169 {
170   TIO2Actors::const_iterator anIter = myIO2Actors.find(theIO);
171   if(anIter != myIO2Actors.end())
172     return anIter->second.GetPointer();
173   return NULL;
174 }
175
176 /*!
177   Adds SALOME_InteractiveObject into selection
178   \param theIO - SALOME_InteractiveObject
179 */
180 bool 
181 SVTK_SelectorDef
182 ::AddIObject(const Handle(SALOME_InteractiveObject)& theIO) 
183 {
184   if(!IsSelected(theIO)){
185     myIObjects.insert(theIO);
186     return true;
187   }
188   return false;
189 }
190
191 /*!
192   Adds SALOME_Actor into selection
193   \param theActor - SALOME_Actor
194 */
195 bool 
196 SVTK_SelectorDef
197 ::AddIObject(SALOME_Actor* theActor) 
198 {
199   const Handle(SALOME_InteractiveObject) anIO = theActor->getIO();
200
201   bool anIsIOBound = IsSelected(anIO);
202   if(!anIsIOBound)
203     myIObjects.insert(anIO);
204
205   bool anIsActorBound = myIO2Actors.find(anIO) != myIO2Actors.end();
206   if(!anIsActorBound)
207     myIO2Actors[anIO] = theActor;
208   
209   return !anIsIOBound || !anIsActorBound;
210 }
211
212 /*!
213   Removes SALOME_InteractiveObject from selection
214   \param theIO - SALOME_InteractiveObject
215 */
216 bool 
217 SVTK_SelectorDef
218 ::RemoveIObject(const Handle(SALOME_InteractiveObject)& theIO) 
219 {
220   bool anIsIOBound = myIObjects.find(theIO) != myIObjects.end();
221
222   myIObjects.erase(theIO);
223   myIO2Actors.erase(theIO);
224   myMapIOSubIndex.erase(theIO);
225
226   return anIsIOBound;
227 }
228
229 /*!
230   Removes SALOME_Actor from selection
231   \param theActor - SALOME_Actor
232 */
233 bool 
234 SVTK_SelectorDef
235 ::RemoveIObject(SALOME_Actor* theActor) 
236 {
237   const Handle(SALOME_InteractiveObject) anIO = theActor->getIO();
238
239   bool anIsActorBound = myIO2Actors.find(anIO) != myIO2Actors.end();
240   if(anIsActorBound)
241     myIO2Actors.erase(anIO);
242
243   return RemoveIObject(anIO) || anIsActorBound;
244 }
245
246 /*!
247   \return list of all SALOME_InteractiveObject presenting in selection
248 */
249 const SALOME_ListIO& 
250 SVTK_SelectorDef
251 ::StoredIObjects() const
252 {
253   myIObjectList.Clear();
254   TIObjects::const_iterator anIter = myIObjects.begin();
255   TIObjects::const_iterator anIterEnd = myIObjects.end();
256   for(; anIter != anIterEnd; anIter++)
257     myIObjectList.Append(*anIter);
258
259   return myIObjectList;
260 }
261
262 /*!
263   \return number of selected objects
264 */
265 int
266 SVTK_SelectorDef
267 ::IObjectCount() const
268 {
269   return myIObjects.size();
270 }
271
272 /*!
273   \return true if the SALOME_InteractiveObject has a subselection
274   \param theIO - SALOME_InteractiveObject
275 */
276 bool 
277 SVTK_SelectorDef
278 ::HasIndex( const Handle(SALOME_InteractiveObject)& theIO) const
279 {
280   return myMapIOSubIndex.find(theIO) != myMapIOSubIndex.end();
281 }
282
283 /*!
284   Gets indices of subselection for SALOME_InteractiveObject
285   \param theIO - SALOME_InteractiveObject
286 */
287 void 
288 SVTK_SelectorDef
289 ::GetIndex( const Handle(SALOME_InteractiveObject)& theIO, 
290             TColStd_IndexedMapOfInteger& theIndex)
291 {
292   TMapIOSubIndex::const_iterator anIter = myMapIOSubIndex.find(theIO);
293   if(anIter != myMapIOSubIndex.end())
294     theIndex = anIter->second.myMap;
295   else
296     theIndex.Clear();
297 }
298
299 /*!
300   \return true if the index presents in subselection 
301   \param theIO - SALOME_InteractiveObject
302   \param theIndex - index
303 */
304 bool
305 SVTK_SelectorDef
306 ::IsIndexSelected(const Handle(SALOME_InteractiveObject)& theIO, 
307                   int theIndex) const
308 {
309   TMapIOSubIndex::const_iterator anIter = myMapIOSubIndex.find(theIO);
310   if(anIter != myMapIOSubIndex.end()){
311     const TColStd_IndexedMapOfInteger& aMapIndex = anIter->second.myMap;
312     return aMapIndex.Contains( theIndex ) == Standard_True;
313   }
314
315   return false;
316 }
317
318 static bool removeIndex(TColStd_IndexedMapOfInteger& theMapIndex, const int theIndex)
319 {
320   int anId = theMapIndex.FindIndex(theIndex); // i==0 if Index is not in the MapIndex
321   if(anId){
322     // only the last key can be removed
323     int aLastId = theMapIndex.FindKey(theMapIndex.Extent());
324     if(aLastId == anId)
325       theMapIndex.RemoveLast();
326     else{
327       TColStd_IndexedMapOfInteger aNewMap;
328       aNewMap.ReSize(theMapIndex.Extent()-1);
329       for(int j = 1; j <= theMapIndex.Extent(); j++){
330         int anIndex = theMapIndex(j);
331         if ( anIndex != theIndex )
332           aNewMap.Add( anIndex );
333       }
334       theMapIndex = aNewMap;
335     }
336   }
337   return anId != 0;
338 }
339
340 /*!
341   Changes indices of subselection for SALOME_InteractiveObject
342   \param theIO - SALOME_InteractiveObject
343   \param theIndices - indices
344   \param theIsModeShift - if it is false, then map will be cleared before indices are added
345 */
346 bool
347 SVTK_SelectorDef
348 ::AddOrRemoveIndex( const Handle(SALOME_InteractiveObject)& theIO, 
349                     const TColStd_IndexedMapOfInteger& theIndices, 
350                     bool theIsModeShift)
351 {
352   TMapIOSubIndex::iterator aMapIter = myMapIOSubIndex.find(theIO);
353   if(aMapIter == myMapIOSubIndex.end()){
354     TIndexedMapOfInteger anEmpty;
355     aMapIter = myMapIOSubIndex.
356       insert(TMapIOSubIndex::value_type(theIO,anEmpty)).first;
357   }
358   TColStd_IndexedMapOfInteger& aMapIndex = aMapIter->second.myMap;
359
360   if(!theIsModeShift)
361     aMapIndex.Clear();
362   
363   for(int i = 1, iEnd = theIndices.Extent(); i <= iEnd; i++)
364     aMapIndex.Add(theIndices(i));
365   
366   if(aMapIndex.IsEmpty()) {
367     myMapIOSubIndex.erase(theIO);
368     return false;
369   }
370
371   return true;
372 }
373
374
375 /*!
376   Changes indices of subselection for SALOME_InteractiveObject
377   \param theIO - SALOME_InteractiveObject
378   \param theIndices - indices
379   \param theIsModeShift - if it is false, then map will be cleared before indices are added
380 */
381 bool
382 SVTK_SelectorDef
383 ::AddOrRemoveIndex( const Handle(SALOME_InteractiveObject)& theIO, 
384                     const TColStd_MapOfInteger& theIndices, 
385                     bool theIsModeShift)
386 {
387   TMapIOSubIndex::iterator aMapIter = myMapIOSubIndex.find(theIO);
388   if(aMapIter == myMapIOSubIndex.end()){
389     TIndexedMapOfInteger anEmpty;
390     aMapIter = myMapIOSubIndex.
391       insert(TMapIOSubIndex::value_type(theIO,anEmpty)).first;
392   }
393   TColStd_IndexedMapOfInteger& aMapIndex = aMapIter->second.myMap;
394
395   if(!theIsModeShift)
396     aMapIndex.Clear();
397   
398   TColStd_MapIteratorOfMapOfInteger anIter(theIndices);
399   for(; anIter.More(); anIter.Next())
400     aMapIndex.Add(anIter.Key());
401   
402   if(aMapIndex.IsEmpty()) {
403     myMapIOSubIndex.erase(theIO);
404     return false;
405   }
406
407   return true;
408 }
409
410
411 /*!
412   Changes indices of subselection for SALOME_InteractiveObject
413   \param theIO - SALOME_InteractiveObject
414   \param theIndex - index
415   \param theIsModeShift - if it is false, then map will be cleared before indices are added
416 */
417 bool 
418 SVTK_SelectorDef
419 ::AddOrRemoveIndex( const Handle(SALOME_InteractiveObject)& theIO, 
420                     int theIndex, 
421                     bool theIsModeShift)
422 {
423   TMapIOSubIndex::iterator anIter = myMapIOSubIndex.find(theIO);
424   if(anIter == myMapIOSubIndex.end()){
425     TIndexedMapOfInteger anEmpty;
426     anIter = myMapIOSubIndex.
427       insert(TMapIOSubIndex::value_type(theIO,anEmpty)).first;
428   }
429   TColStd_IndexedMapOfInteger& aMapIndex = anIter->second.myMap;
430
431   bool anIsConatains = aMapIndex.Contains( theIndex ) == Standard_True;
432   if ( anIsConatains )
433     removeIndex( aMapIndex, theIndex );
434   
435   if ( !theIsModeShift )
436     aMapIndex.Clear();
437   
438   if ( !anIsConatains )
439     aMapIndex.Add( theIndex );
440
441   if ( aMapIndex.IsEmpty() )
442     myMapIOSubIndex.erase( theIO );
443
444   return false;
445 }
446
447
448 /*!
449   Removes index of subselection for SALOME_InteractiveObject
450   \param theIO - SALOME_InteractiveObject
451   \param theIndex - index
452 */
453 void
454 SVTK_SelectorDef
455 ::RemoveIndex( const Handle(SALOME_InteractiveObject)& theIO, 
456                int theIndex)
457 {
458   if(IsIndexSelected(theIO,theIndex)){
459     TMapIOSubIndex::iterator anIter = myMapIOSubIndex.find(theIO);
460     TColStd_IndexedMapOfInteger& aMapIndex = anIter->second.myMap;
461     removeIndex(aMapIndex,theIndex);
462   }
463 }
464
465 /*!
466   Clears all indices of subselection
467 */
468 void 
469 SVTK_SelectorDef
470 ::ClearIndex()
471 {
472   myMapIOSubIndex.clear();  
473 }
474
475 /*!
476   To apply a filter on the selection
477   \param theFilter - new filter
478 */
479 void
480 SVTK_SelectorDef
481 ::SetFilter(const Handle(VTKViewer_Filter)& theFilter)
482 {
483   myFilters.insert(TFilters::value_type(theFilter->GetId(),theFilter));
484 }
485
486 /*!
487   \return true if filter with given number is applyed
488   \param theId - filter id
489 */
490 bool
491 SVTK_SelectorDef
492 ::IsFilterPresent(const TFilterID theId) const
493 {
494   return myFilters.find(theId) != myFilters.end();
495 }
496
497 /*!
498   To remove a filter from the selection
499   \param theId - filter id
500 */
501 void  
502 SVTK_SelectorDef
503 ::RemoveFilter(const TFilterID theId)
504 {
505   if(IsFilterPresent(theId))
506     myFilters.erase(theId);
507 }
508
509 /*!
510   \return true if the index satisfy installed filters
511   \param theActor - actor
512   \param theId - filter id
513   \param theIsNode - whether it is node
514 */
515 bool
516 SVTK_SelectorDef
517 ::IsValid(SALOME_Actor* theActor,
518           const TFilterID theId,
519           const bool theIsNode) const
520 {
521   TFilters::const_iterator anIter = myFilters.begin();
522   for(; anIter != myFilters.end(); ++anIter){
523     const Handle(VTKViewer_Filter)& aFilter = anIter->second;
524     if(theIsNode == aFilter->IsNodeFilter() &&
525        !aFilter->IsValid(theActor,theId))
526       return false;
527   }
528   return true;
529 }
530
531 /*!
532   \return filter by it's id
533   \param theId - filter id
534 */
535 Handle(VTKViewer_Filter) 
536 SVTK_SelectorDef
537 ::GetFilter(const TFilterID theId) const
538 {
539   TFilters::const_iterator anIter = myFilters.find(theId);
540   if(anIter != myFilters.end()){
541     const Handle(VTKViewer_Filter)& aFilter = anIter->second;
542     return aFilter;
543   }
544   return Handle(VTKViewer_Filter)();
545 }
546
547 SALOME_Actor*
548 SVTK_SelectorDef
549 ::Pick(const SVTK_SelectionEvent* theEvent, vtkRenderer* theRenderer) const
550 {
551   bool anAdvancedSelectionAlgorithm = true;
552   SUIT_ResourceMgr* aResourceMgr = SUIT_Session::session()->resourceMgr();
553   if ( aResourceMgr )
554     anAdvancedSelectionAlgorithm = aResourceMgr->booleanValue( "VTKViewer", "use_advanced_selection_algorithm", true );
555
556   SALOME_Actor* anActor = NULL;
557   vtkActorCollection* aListActors = NULL;
558   if ( anAdvancedSelectionAlgorithm ) {
559     myCellPicker->Pick(theEvent->myX,
560                        theEvent->myY, 
561                        0.0,
562                        theRenderer);
563   
564     aListActors = myCellPicker->GetActors();
565     anActor = GetLastSALOMEActor(aListActors);
566   }
567
568   if ( !anActor ) {
569     myPicker->Pick(theEvent->myX,
570                    theEvent->myY, 
571                    0.0,
572                    theRenderer);
573     aListActors = myPicker->GetActors();
574     anActor = GetLastSALOMEActor(aListActors);
575   }
576   
577   return anActor;
578 }
579
580 void
581 SVTK_SelectorDef
582 ::SetTolerance(const double& theTolerance) 
583 {
584   myPicker->SetTolerance(theTolerance);         
585   myCellPicker->SetTolerance(theTolerance);
586 }