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