1 // Copyright (C) 2007-2023 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
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.
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.
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
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 // SALOME SALOMEGUI : implementation of desktop and GUI kernel
24 // File : SALOME_Selection.cxx
25 // Author : Nicolas REJNERI
26 #include "SVTK_SelectorDef.h"
28 #include <VTKViewer_Filter.h>
30 #include "SALOME_Actor.h"
32 #include <SUIT_Session.h>
33 #include <SUIT_ResourceMgr.h>
35 #include <TColStd_MapIteratorOfMapOfInteger.hxx>
36 #include <TColStd_IndexedMapOfInteger.hxx>
38 #include <vtkCallbackCommand.h>
39 #include <vtkActorCollection.h>
40 #include <vtkCellPicker.h>
44 \return new SVTK_Selector
50 return new SVTK_SelectorDef();
58 myPicker(vtkPicker::New()),
59 myCellPicker(vtkCellPicker::New())
61 mySelectionMode = ActorSelection;
62 myDynamicPreselection = true;
63 myPreselectionEnabled = true;
64 mySelectionEnabled = true;
67 myCellPicker->Delete();
79 To invoke selectionChanged signals
85 this->InvokeEvent(vtkCommand::StartPickEvent,NULL);
89 To invoke selectionChanged signals
95 this->InvokeEvent(vtkCommand::EndPickEvent,NULL);
99 To change current Selection_Mode (as outside effect, it invokes selectionChange signal)
103 ::SetSelectionMode(Selection_Mode theMode)
105 if(mySelectionMode != theMode){
106 mySelectionMode = theMode;
107 myMapIOSubIndex.clear();
108 myMapIOSubCompositeIndex.clear();
109 this->EndPickCallback();
122 myMapIOSubIndex.clear();
123 myMapIOSubCompositeIndex.clear();
127 \return true if the SALOME_InteractiveObject presents into selection
131 ::IsSelected(const Handle(SALOME_InteractiveObject)& theIO) const
133 return !theIO.IsNull() && (myIObjects.find(theIO) != myIObjects.end());
137 \return true if the SALOME_Actor presents into selection
141 ::IsSelected(SALOME_Actor* theActor) const
143 const Handle(SALOME_InteractiveObject) anIO = theActor->getIO();
144 return IsSelected(anIO) && myIO2Actors.find(anIO) != myIO2Actors.end();
148 \return corresponding SALOME_Actor for SALOME_InteractiveObject
149 \param theIO - SALOME_InteractiveObject
153 ::GetActor(const Handle(SALOME_InteractiveObject)& theIO) const
155 TIO2Actors::const_iterator anIter = myIO2Actors.find(theIO);
156 if(anIter != myIO2Actors.end())
157 return anIter->second.GetPointer();
162 Adds SALOME_InteractiveObject into selection
163 \param theIO - SALOME_InteractiveObject
167 ::AddIObject(const Handle(SALOME_InteractiveObject)& theIO)
169 if(!IsSelected(theIO)){
170 myIObjects.insert(theIO);
177 Adds SALOME_Actor into selection
178 \param theActor - SALOME_Actor
182 ::AddIObject(SALOME_Actor* theActor)
184 const Handle(SALOME_InteractiveObject) anIO = theActor->getIO();
186 bool anIsIOBound = IsSelected(anIO);
188 myIObjects.insert(anIO);
190 bool anIsActorBound = myIO2Actors.find(anIO) != myIO2Actors.end();
192 myIO2Actors[anIO] = theActor;
194 return !anIsIOBound || !anIsActorBound;
198 Removes SALOME_InteractiveObject from selection
199 \param theIO - SALOME_InteractiveObject
203 ::RemoveIObject(const Handle(SALOME_InteractiveObject)& theIO)
205 bool anIsIOBound = myIObjects.find(theIO) != myIObjects.end();
207 myIObjects.erase(theIO);
208 myIO2Actors.erase(theIO);
209 myMapIOSubIndex.erase(theIO);
210 myMapIOSubCompositeIndex.erase(theIO);
216 Removes SALOME_Actor from selection
217 \param theActor - SALOME_Actor
221 ::RemoveIObject(SALOME_Actor* theActor)
223 const Handle(SALOME_InteractiveObject) anIO = theActor->getIO();
225 bool anIsActorBound = myIO2Actors.find(anIO) != myIO2Actors.end();
227 myIO2Actors.erase(anIO);
229 return RemoveIObject(anIO) || anIsActorBound;
233 \return list of all SALOME_InteractiveObject presenting in selection
237 ::StoredIObjects() const
239 myIObjectList.Clear();
240 TIObjects::const_iterator anIter = myIObjects.begin();
241 TIObjects::const_iterator anIterEnd = myIObjects.end();
242 for(; anIter != anIterEnd; anIter++)
243 myIObjectList.Append(*anIter);
245 return myIObjectList;
249 \return number of selected objects
253 ::IObjectCount() const
255 return (int)myIObjects.size(); //!< TODO: conversion from size_t to int
259 \return true if the SALOME_InteractiveObject has a subselection
260 \param theIO - SALOME_InteractiveObject
264 ::HasIndex( const Handle(SALOME_InteractiveObject)& theIO) const
266 return myMapIOSubIndex.find(theIO) != myMapIOSubIndex.end();
270 Gets indices of subselection for SALOME_InteractiveObject
271 \param theIO - SALOME_InteractiveObject
275 ::GetIndex( const Handle(SALOME_InteractiveObject)& theIO,
276 SVTK_TIndexedMapOfVtkId& theIndex)
278 TMapIOSubIndex::const_iterator anIter = myMapIOSubIndex.find(theIO);
279 if(anIter != myMapIOSubIndex.end())
280 theIndex = anIter->second.myMap;
286 \return true if the index presents in subselection
287 \param theIO - SALOME_InteractiveObject
288 \param theIndex - index
292 ::IsIndexSelected(const Handle(SALOME_InteractiveObject)& theIO,
295 TMapIOSubIndex::const_iterator anIter = myMapIOSubIndex.find(theIO);
296 if(anIter != myMapIOSubIndex.end()){
297 const SVTK_TIndexedMapOfVtkId& aMapIndex = anIter->second.myMap;
298 return aMapIndex.Contains( theIndex ) == Standard_True;
304 static bool removeIndex(SVTK_TIndexedMapOfVtkId& theMapIndex, const int theIndex)
306 int anId = theMapIndex.FindIndex(theIndex); // i==0 if Index is not in the MapIndex
308 // only the last key can be removed
309 int aLastId = theMapIndex.FindKey(theMapIndex.Extent());
311 theMapIndex.RemoveLast();
313 SVTK_TIndexedMapOfVtkId aNewMap;
314 aNewMap.ReSize(theMapIndex.Extent()-1);
315 for(int j = 1; j <= theMapIndex.Extent(); j++){
316 int anIndex = theMapIndex(j);
317 if ( anIndex != theIndex )
318 aNewMap.Add( anIndex );
320 theMapIndex = aNewMap;
326 static bool removeCompositeIndex( SVTK_IndexedMapOfVtkIds& theMapIndex, const SVTK_ListOfVtk theIds )
328 int anId = theMapIndex.FindIndex( theIds ); // i==0 if Index is not in the MapIndex
330 // only the last key can be removed
331 SVTK_ListOfVtk aLastIds = theMapIndex.FindKey( theMapIndex.Extent() );
332 if( aLastIds == theIds )
333 theMapIndex.RemoveLast();
335 SVTK_IndexedMapOfVtkIds aNewMap;
336 aNewMap.ReSize(theMapIndex.Extent()-1);
337 for( int j = 1; j <= theMapIndex.Extent(); j++ ){
338 SVTK_ListOfVtk anIds = theMapIndex( j );
339 if ( anIds != theIds )
340 aNewMap.Add( anIds );
342 theMapIndex = aNewMap;
350 Changes indices of subselection for SALOME_InteractiveObject
351 \param theIO - SALOME_InteractiveObject
352 \param theIndices - indices
353 \param theIsModeShift - if it is false, then map will be cleared before indices are added
357 ::AddOrRemoveIndex( const Handle(SALOME_InteractiveObject)& theIO,
358 const SVTK_TIndexedMapOfVtkId& theIndices,
361 TMapIOSubIndex::iterator aMapIter = myMapIOSubIndex.find(theIO);
362 if(aMapIter == myMapIOSubIndex.end()){
363 TIndexedMapOfInteger anEmpty;
364 aMapIter = myMapIOSubIndex.
365 insert(TMapIOSubIndex::value_type(theIO,anEmpty)).first;
367 SVTK_TIndexedMapOfVtkId& aMapIndex = aMapIter->second.myMap;
372 for(int i = 1, iEnd = theIndices.Extent(); i <= iEnd; i++)
373 aMapIndex.Add(theIndices(i));
375 if(aMapIndex.IsEmpty()) {
376 myMapIOSubIndex.erase(theIO);
385 Changes indices of subselection for SALOME_InteractiveObject
386 \param theIO - SALOME_InteractiveObject
387 \param theIndices - indices
388 \param theIsModeShift - if it is false, then map will be cleared before indices are added
392 ::AddOrRemoveIndex( const Handle(SALOME_InteractiveObject)& theIO,
393 const SVTK_TVtkIDsMap& theIndices,
396 TMapIOSubIndex::iterator aMapIter = myMapIOSubIndex.find(theIO);
397 if(aMapIter == myMapIOSubIndex.end()){
398 TIndexedMapOfInteger anEmpty;
399 aMapIter = myMapIOSubIndex.
400 insert(TMapIOSubIndex::value_type(theIO,anEmpty)).first;
402 SVTK_TIndexedMapOfVtkId& aMapIndex = aMapIter->second.myMap;
407 SVTK_TVtkIDsMapIterator anIter(theIndices);
408 for(; anIter.More(); anIter.Next())
409 aMapIndex.Add(anIter.Key());
411 if(aMapIndex.IsEmpty()) {
412 myMapIOSubIndex.erase(theIO);
421 Changes indices of subselection for SALOME_InteractiveObject
422 \param theIO - SALOME_InteractiveObject
423 \param theIndex - index
424 \param theIsModeShift - if it is false, then map will be cleared before indices are added
428 ::AddOrRemoveIndex( const Handle(SALOME_InteractiveObject)& theIO,
432 TMapIOSubIndex::iterator anIter = myMapIOSubIndex.find(theIO);
433 if(anIter == myMapIOSubIndex.end()){
434 TIndexedMapOfInteger anEmpty;
435 anIter = myMapIOSubIndex.
436 insert(TMapIOSubIndex::value_type(theIO,anEmpty)).first;
438 SVTK_TIndexedMapOfVtkId& aMapIndex = anIter->second.myMap;
440 bool anIsConatains = aMapIndex.Contains( theIndex ) == Standard_True;
442 removeIndex( aMapIndex, theIndex );
444 if ( !theIsModeShift )
447 if ( !anIsConatains )
448 aMapIndex.Add( theIndex );
450 if ( aMapIndex.IsEmpty() )
451 myMapIOSubIndex.erase( theIO );
458 Removes index of subselection for SALOME_InteractiveObject
459 \param theIO - SALOME_InteractiveObject
460 \param theIndex - index
464 ::RemoveIndex( const Handle(SALOME_InteractiveObject)& theIO,
467 if(IsIndexSelected(theIO,theIndex)){
468 TMapIOSubIndex::iterator anIter = myMapIOSubIndex.find(theIO);
469 SVTK_TIndexedMapOfVtkId& aMapIndex = anIter->second.myMap;
470 removeIndex(aMapIndex,theIndex);
475 Clears all indices of subselection
481 myMapIOSubIndex.clear();
485 \return true if the SALOME_InteractiveObject has a composite index subselection
486 \param theIO - SALOME_InteractiveObject
490 ::HasCompositeIndex( const Handle(SALOME_InteractiveObject)& theIO ) const
492 return myMapIOSubCompositeIndex.find( theIO ) != myMapIOSubCompositeIndex.end();
496 Gets composite indices of subselection for SALOME_InteractiveObject
497 \param theIO - SALOME_InteractiveObject
501 ::GetCompositeIndex( const Handle(SALOME_InteractiveObject)& theIO,
502 SVTK_IndexedMapOfVtkIds& theIds )
504 TMapIOSubCompositeIndex::const_iterator anIter = myMapIOSubCompositeIndex.find( theIO );
505 if( anIter != myMapIOSubCompositeIndex.end() )
506 theIds = anIter->second;
512 Changes composite indices of subselection for SALOME_InteractiveObject
513 \param theIO - SALOME_InteractiveObject
514 \param theIndices - composite id
515 \param theIsModeShift - if it is false, then map will be cleared before indices are added
519 ::AddOrRemoveCompositeIndex( const Handle( SALOME_InteractiveObject )& theIO,
520 const SVTK_IndexedMapOfVtkIds& theIds,
523 TMapIOSubCompositeIndex::iterator aMapIter = myMapIOSubCompositeIndex.find( theIO );
524 if( aMapIter == myMapIOSubCompositeIndex.end() ) {
525 SVTK_IndexedMapOfVtkIds anEmpty;
526 aMapIter = myMapIOSubCompositeIndex.insert( TMapIOSubCompositeIndex::value_type( theIO, anEmpty ) ).first;
528 SVTK_IndexedMapOfVtkIds& aMapIndex = aMapIter->second;
530 if( !theIsModeShift )
533 for( int i = 1, iEnd = theIds.Extent(); i <= iEnd; i++ )
534 aMapIndex.Add( theIds( i ) );
536 if( aMapIndex.IsEmpty() ) {
537 myMapIOSubCompositeIndex.erase( theIO );
544 Changes indices of subselection for SALOME_InteractiveObject
545 \param theIO - SALOME_InteractiveObject
546 \param theIds - composite ids
547 \param theIsModeShift - if it is false, then map will be cleared before indices are added
551 ::AddOrRemoveCompositeIndex( const Handle(SALOME_InteractiveObject)& theIO,
552 SVTK_ListOfVtk theIds,
555 TMapIOSubCompositeIndex::iterator anIter = myMapIOSubCompositeIndex.find( theIO );
556 if( anIter == myMapIOSubCompositeIndex.end() ) {
557 SVTK_IndexedMapOfVtkIds anEmpty;
558 anIter = myMapIOSubCompositeIndex.insert(TMapIOSubCompositeIndex::value_type( theIO,anEmpty ) ).first;
561 SVTK_IndexedMapOfVtkIds& aMapIndex = anIter->second;
563 bool anIsContains = aMapIndex.Contains( theIds ) == Standard_True;
565 removeCompositeIndex( aMapIndex, theIds );
567 if ( !theIsModeShift )
571 aMapIndex.Add( theIds );
573 if ( aMapIndex.IsEmpty() )
574 myMapIOSubIndex.erase( theIO );
580 Removes composite index of subselection for SALOME_InteractiveObject
581 \param theIO - SALOME_InteractiveObject
582 \param theIds - index
586 ::RemoveCompositeIndex( const Handle(SALOME_InteractiveObject)& theIO,
587 SVTK_ListOfVtk theIds )
589 if(IsCompositeIndexSelected( theIO, theIds ) ) {
590 TMapIOSubCompositeIndex::iterator anIter = myMapIOSubCompositeIndex.find( theIO );
591 SVTK_IndexedMapOfVtkIds& aMapIndex = anIter->second;
592 removeCompositeIndex( aMapIndex,theIds );
597 \return true if the composite index presents in subselection
598 \param theIO - SALOME_InteractiveObject
599 \param theIds - index
603 ::IsCompositeIndexSelected( const Handle(SALOME_InteractiveObject)& theIO,
604 SVTK_ListOfVtk theIds ) const
606 TMapIOSubCompositeIndex::const_iterator anIter = myMapIOSubCompositeIndex.find( theIO );
607 if( anIter != myMapIOSubCompositeIndex.end() ) {
608 const SVTK_IndexedMapOfVtkIds& aMapIndex = anIter->second;
609 return aMapIndex.Contains( theIds ) == Standard_True;
615 Clears all composite indices of subselection
619 ::ClearCompositeIndex()
621 myMapIOSubCompositeIndex.clear();
626 To apply a filter on the selection
627 \param theFilter - new filter
631 ::SetFilter(const Handle(VTKViewer_Filter)& theFilter)
633 myFilters.insert(TFilters::value_type(theFilter->GetId(),theFilter));
637 \return true if filter with given number is applyed
638 \param theId - filter id
642 ::IsFilterPresent(const TFilterID theId) const
644 return myFilters.find(theId) != myFilters.end();
648 To remove a filter from the selection
649 \param theId - filter id
653 ::RemoveFilter(const TFilterID theId)
655 if(IsFilterPresent(theId))
656 myFilters.erase(theId);
660 \return true if the index satisfy installed filters
661 \param theActor - actor
662 \param theId - filter id
663 \param theIsNode - whether it is node
667 ::IsValid(SALOME_Actor* theActor,
668 const TFilterID theId,
669 const bool theIsNode) const
671 TFilters::const_iterator anIter = myFilters.begin();
672 for(; anIter != myFilters.end(); ++anIter){
673 const Handle(VTKViewer_Filter)& aFilter = anIter->second;
674 if(theIsNode == aFilter->IsNodeFilter() &&
675 !aFilter->IsValid(theActor,theId))
682 \return filter by it's id
683 \param theId - filter id
685 Handle(VTKViewer_Filter)
687 ::GetFilter(const TFilterID theId) const
689 TFilters::const_iterator anIter = myFilters.find(theId);
690 if(anIter != myFilters.end()){
691 const Handle(VTKViewer_Filter)& aFilter = anIter->second;
694 return Handle(VTKViewer_Filter)();
699 ::Pick(const SVTK_SelectionEvent* theEvent, vtkRenderer* theRenderer) const
701 vtkActorCollection* aListActors = NULL;
703 if ( GetDynamicPreSelection() ) {
704 myCellPicker->Pick(theEvent->myX,
709 aListActors = myCellPicker->GetActors();
712 if ( !aListActors || !aListActors->GetNumberOfItems() ) {
713 myPicker->Pick(theEvent->myX,
717 aListActors = myPicker->GetActors();
725 ::SetTolerance(const double& theTolerance)
727 myPicker->SetTolerance(theTolerance);
728 myCellPicker->SetTolerance(theTolerance);
733 ::SetDynamicPreSelection( bool theIsDynPreselect )
735 myDynamicPreselection = theIsDynPreselect;
740 ::GetDynamicPreSelection() const
742 return myDynamicPreselection;
747 ::SetPreSelectionEnabled( bool theEnabled )
749 myPreselectionEnabled = theEnabled;
754 ::IsPreSelectionEnabled() const
756 return mySelectionEnabled && myPreselectionEnabled;
761 ::SetSelectionEnabled( bool theEnabled )
763 mySelectionEnabled = theEnabled;
768 ::IsSelectionEnabled() const
770 return mySelectionEnabled;