1112be9715ea6f1bc5c0fea6a4087f529c1610de
[occt.git] / src / NIS / NIS_InteractiveContext.cxx
1 // Created on: 2007-07-06
2 // Created by: Alexander GRIGORIEV
3 // Copyright (c) 2007-2014 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 #include <NIS_InteractiveContext.hxx>
17 #include <NIS_InteractiveObject.hxx>
18 #include <NIS_View.hxx>
19 #include <TColStd_MapIteratorOfPackedMapOfInteger.hxx>
20 #include <Standard_NoSuchObject.hxx>
21 #include <Bnd_B2f.hxx>
22
23 IMPLEMENT_STANDARD_HANDLE  (NIS_InteractiveContext, Standard_Transient)
24 IMPLEMENT_STANDARD_RTTIEXT (NIS_InteractiveContext, Standard_Transient)
25
26 static void markAllDrawersUpdated   (const NCollection_Map<Handle_NIS_Drawer>&);
27
28 //=======================================================================
29 //function : NIS_InteractiveContext()
30 //purpose  : Constructor
31 //=======================================================================
32
33 NIS_InteractiveContext::NIS_InteractiveContext ()
34   : myAllocator       (new NIS_Allocator(1024*100)),
35     myLastObjectId    (0),
36     myObjects         (1000),
37 //     myDrawers       (101, myAllocator),
38     mySelectionMode   (Mode_NoSelection),
39     myIsShareDrawList (Standard_True)
40 {
41   // ID == 0 is invalid so we reserve this item from subsequent allocation.
42   myObjects.SetValue(myLastObjectId, NULL);
43 }
44
45 //=======================================================================
46 //function : ~NIS_InteractiveContext
47 //purpose  : Destructor
48 //=======================================================================
49
50 NIS_InteractiveContext::~NIS_InteractiveContext ()
51 {
52   // Unregister this context in all referred views
53   NCollection_List<Handle_NIS_View>::Iterator anIterV (myViews);
54   for (; anIterV.More(); anIterV.Next())
55     if (anIterV.Value().IsNull() == Standard_False)
56       anIterV.Value()->RemoveContext(this);
57
58 //   // Unregister this context in all referred drawers
59 //   NCollection_Map<Handle_NIS_Drawer>::Iterator anIterD (myDrawers);
60 //   for (; anIterD.More(); anIterD.Next())
61 //     if (anIterD.Value().IsNull() == Standard_False)
62 //       anIterD.Value()->myCtx = 0L;
63 }
64
65
66 //=======================================================================
67 //function : AttachView
68 //purpose  : 
69 //=======================================================================
70
71 void NIS_InteractiveContext::AttachView (const Handle_NIS_View& theView)
72 {
73   if (theView.IsNull() == Standard_False) {
74     NCollection_List<Handle_NIS_View>::Iterator anIter (myViews);
75     for (; anIter.More(); anIter.Next())
76       if (anIter.Value() == theView)
77         break;
78     if (anIter.More() == Standard_False) {
79       myViews.Append (theView);
80       theView->AddContext (this);
81       NCollection_Map<Handle_NIS_Drawer>::Iterator anIterD (myDrawers);
82       for (; anIterD.More(); anIterD.Next()) {
83         const Handle(NIS_Drawer)& aDrawer = anIterD.Value();
84         if (aDrawer.IsNull() == Standard_False)
85           aDrawer->myLists.Append(aDrawer->createDefaultList(theView));
86       }
87     }
88   }
89 }
90
91 //=======================================================================
92 //function : DetachView
93 //purpose  : 
94 //=======================================================================
95
96 void NIS_InteractiveContext::DetachView (const Handle_NIS_View& theView)
97 {
98   if (theView.IsNull() == Standard_False) {
99     NCollection_List<Handle_NIS_View>::Iterator anIter (myViews);
100     for (; anIter.More(); anIter.Next())
101       if (anIter.Value() == theView) {
102         myViews.Remove(anIter);
103         theView->RemoveContext(this);
104         NCollection_Map<Handle_NIS_Drawer>::Iterator anIterD (myDrawers);
105         for (; anIterD.More(); anIterD.Next()) {
106           const Handle(NIS_Drawer)& aDrawer = anIterD.Value();
107           if (aDrawer.IsNull() == Standard_False) {
108             NCollection_List<NIS_DrawList*>::Iterator anIterL(aDrawer->myLists);
109             for (; anIterL.More(); anIterL.Next())
110               if (anIterL.Value()->GetView() == theView) {
111                 delete anIterL.Value();
112                 aDrawer->myLists.Remove (anIterL);
113                 break;
114               }
115           }
116         }
117         break;
118       }
119   }
120 }
121
122 //=======================================================================
123 //function : GetObject
124 //purpose  : 
125 //=======================================================================
126
127 const Handle_NIS_InteractiveObject& NIS_InteractiveContext::GetObject
128                    (const Standard_Integer theID) const
129 {
130   if (!myObjects.IsBound(theID))
131   {
132     static Handle_NIS_InteractiveObject aNull;
133     return aNull;
134   }
135   return myObjects(theID);
136 }
137
138 //=======================================================================
139 //function : redraw
140 //purpose  : 
141 //=======================================================================
142
143 void NIS_InteractiveContext::redraw (const Handle(NIS_View)&    theView,
144                                      const NIS_Drawer::DrawType theType)
145 {
146   NCollection_Map <Handle_NIS_Drawer>::Iterator anIter (myDrawers);
147   for (; anIter.More(); anIter.Next())
148     if (anIter.Value().IsNull() == Standard_False)
149       anIter.Value()->redraw (theType, theView);
150 }
151
152 //=======================================================================
153 //function : GetBox
154 //purpose  : 
155 //=======================================================================
156
157 void NIS_InteractiveContext::GetBox (Bnd_B3f&         theBox,
158                                      const NIS_View * theView) const
159 {
160   NCollection_Map <Handle_NIS_Drawer>::Iterator anIterD (myDrawers);
161   for (; anIterD.More(); anIterD.Next())
162     if (anIterD.Value().IsNull() == Standard_False)
163       theBox.Add(anIterD.Value()->GetBox(theView));
164 }
165
166 //=======================================================================
167 //function : Display
168 //purpose  : 
169 //=======================================================================
170
171 void NIS_InteractiveContext::Display
172                                 (Handle_NIS_InteractiveObject& theObj,
173                                  const Handle_NIS_Drawer&      theDrawer,
174                                  const Standard_Boolean        isUpdateViews)
175 {
176   if (theObj.IsNull())
177     return;
178   objectForDisplay(theObj, theObj->DrawType());
179   const Handle(NIS_Drawer)& aDrawer = drawerForDisplay(theObj, theDrawer);
180   // Display Object as Normal or Transparent if it has been hidden
181   if (theObj->IsHidden())
182     theObj->myIsHidden = Standard_False;
183
184   // Set Update flag in the Drawer
185   if (isUpdateViews)
186     aDrawer->SetUpdated (theObj->DrawType());
187 }
188
189 //=======================================================================
190 //function : DisplayOnTop
191 //purpose  : 
192 //=======================================================================
193
194 void NIS_InteractiveContext::DisplayOnTop
195                                 (Handle_NIS_InteractiveObject& theObj,
196                                  const Handle_NIS_Drawer&      theDrawer,
197                                  const Standard_Boolean        isUpdateViews)
198 {
199   if (theObj.IsNull())
200     return;
201
202   objectForDisplay(theObj, NIS_Drawer::Draw_Top);
203   const Handle(NIS_Drawer)& aDrawer = drawerForDisplay(theObj, theDrawer);
204
205   // Display Object as Normal or Transparent if it has been hidden
206   if (theObj->IsHidden())
207     theObj->myIsHidden = Standard_False;
208
209   // Set Update flag in the Drawer
210   if (isUpdateViews)
211     aDrawer->SetUpdated (theObj->DrawType());
212 }
213
214 //=======================================================================
215 //function : Erase
216 //purpose  : 
217 //=======================================================================
218
219 void NIS_InteractiveContext::Erase (const Handle_NIS_InteractiveObject& theObj,
220                                     const Standard_Boolean isUpdateViews)
221 {
222   if (theObj->IsHidden() == Standard_False) {
223     theObj->myIsHidden = Standard_True;
224     const Handle(NIS_Drawer)& aDrawer = theObj->GetDrawer();
225     if (aDrawer.IsNull() == Standard_False) {
226       // Unhilight the erased object
227       if (theObj->IsDynHilighted()) {
228         NCollection_List<Handle_NIS_View>::Iterator anIterV (myViews);
229         for (; anIterV.More(); anIterV.Next())
230           if (anIterV.Value().IsNull() == Standard_False)
231             anIterV.Value()->DynamicUnhilight (theObj);
232       }
233       // Update status of lists
234       if (isUpdateViews)
235         aDrawer->SetUpdated(theObj->DrawType());
236     }
237   }
238 }
239
240 //=======================================================================
241 //function : Remove
242 //purpose  : 
243 //=======================================================================
244
245 void NIS_InteractiveContext::Remove (const Handle_NIS_InteractiveObject& theObj,
246                                      const Standard_Boolean isUpdateViews)
247 {
248   if (theObj.IsNull() == Standard_False) {
249     const Handle(NIS_Drawer)& aDrawer = theObj->GetDrawer();
250     if ( aDrawer.IsNull() )
251       return;
252     if (aDrawer->myCtx == this) {
253       // Remove the hilighting if the object has been hilighted
254       if (theObj->IsDynHilighted()) {
255         NCollection_List<Handle_NIS_View>::Iterator anIterV (myViews);
256         for (; anIterV.More(); anIterV.Next())
257           if (anIterV.Value().IsNull() == Standard_False)
258             anIterV.Value()->DynamicUnhilight (theObj);
259       }
260       // Remove the object from the context
261       const Standard_Integer anID = theObj->ID();
262       const NIS_Drawer::DrawType aDrawType (theObj->DrawType()); 
263       if (myMapObjects[Standard_Integer(aDrawType)].Remove(anID))
264         aDrawer->removeObject(theObj.operator->(), isUpdateViews);
265       theObj->myID = 0;
266       theObj->myDrawer.Nullify();
267       myObjects.UnsetValue(anID);
268       myMapNonSelectableObjects.Remove(anID);
269     }
270   }
271 }
272
273 //=======================================================================
274 //function : DisplayAll
275 //purpose  : 
276 //=======================================================================
277
278 void NIS_InteractiveContext::DisplayAll ()
279 {
280   // UnHide all objects in the Context
281   NCollection_SparseArray <Handle_NIS_InteractiveObject>::ConstIterator
282     anIter(myObjects);
283   for (; anIter.More(); anIter.Next()) {
284     const Handle(NIS_InteractiveObject)& anObj = anIter.Value();
285     if (anObj.IsNull() == Standard_False)
286       if (anObj->IsHidden())
287         anObj->myIsHidden = Standard_False;
288   }
289
290   // Update status of objects in Drawers (particularly cancel dyn. hilighting)
291   NCollection_Map<Handle_NIS_Drawer>::Iterator anIterD (myDrawers);
292   for (; anIterD.More(); anIterD.Next()) {
293     const Handle(NIS_Drawer)& aDrawer = anIterD.Value();
294     if (aDrawer.IsNull() == Standard_False) {
295       aDrawer->SetUpdated (NIS_Drawer::Draw_Normal,
296                            NIS_Drawer::Draw_Top,
297                            NIS_Drawer::Draw_Transparent,
298                            NIS_Drawer::Draw_Hilighted);
299     }
300   }
301 }
302
303 //=======================================================================
304 //function : EraseAll
305 //purpose  : 
306 //=======================================================================
307
308 void NIS_InteractiveContext::EraseAll ()
309 {
310   // Hide all objects in the Context
311   NCollection_SparseArray <Handle_NIS_InteractiveObject>::ConstIterator
312     anIter(myObjects);
313   for (; anIter.More(); anIter.Next()) {
314     const Handle(NIS_InteractiveObject)& anObj = anIter.Value();
315     if (anObj.IsNull() == Standard_False) {
316       if (anObj->IsHidden() == Standard_False)
317         anObj->myIsHidden = Standard_True;
318       if (anObj->IsDynHilighted()) {
319         NCollection_List<Handle_NIS_View>::Iterator anIterV (myViews);
320         for (; anIterV.More(); anIterV.Next())
321           if (anIterV.Value().IsNull() == Standard_False)
322             anIterV.Value()->DynamicUnhilight (anObj);
323       }
324     }
325   }
326
327   // Update status of objects in Drawers (particularly cancel dyn. hilighting)
328   NCollection_Map<Handle_NIS_Drawer>::Iterator anIterD (myDrawers);
329   for (; anIterD.More(); anIterD.Next()) {
330     const Handle(NIS_Drawer)& aDrawer = anIterD.Value();
331     if (aDrawer.IsNull() == Standard_False) {
332       aDrawer->SetUpdated (NIS_Drawer::Draw_Normal,
333                            NIS_Drawer::Draw_Top,
334                            NIS_Drawer::Draw_Transparent,
335                            NIS_Drawer::Draw_Hilighted);
336 //         if (aList.myDynHilighted.IsEmpty() == Standard_False) {
337 //           aList.myIsUpdated[NIS_Drawer::Draw_DynHilighted]= Standard_True;
338 //           aList.myDynHilighted.Clear();
339 //         }
340
341     }
342   }
343 }
344
345 //=======================================================================
346 //function : RemoveAll
347 //purpose  : 
348 //=======================================================================
349
350 void NIS_InteractiveContext::RemoveAll ()
351 {
352   // Remove objects from the Context
353   NCollection_SparseArray <Handle_NIS_InteractiveObject>::Iterator
354     anIter(myObjects);
355   for (; anIter.More(); anIter.Next()) {
356     Handle(NIS_InteractiveObject)& anObj = anIter.ChangeValue();
357     if (anObj.IsNull() == Standard_False) {
358       if (anObj->IsDynHilighted()) {
359         NCollection_List<Handle_NIS_View>::Iterator anIterV (myViews);
360         for (; anIterV.More(); anIterV.Next())
361           if (anIterV.Value().IsNull() == Standard_False)
362             anIterV.Value()->DynamicUnhilight (anObj);
363       }
364       anObj->myID = 0;
365       anObj->myDrawer.Nullify();
366       anObj.Nullify();
367     }
368   }
369
370   // Mark all draw lists to be removed in the view callback
371   NCollection_Map<Handle_NIS_Drawer>::Iterator anIterD (myDrawers);
372   for (; anIterD.More(); anIterD.Next()) {
373     const Handle(NIS_Drawer)& aDrawer = anIterD.Value();
374     if (aDrawer.IsNull() == Standard_False) {
375       aDrawer->myMapID.Clear();
376       aDrawer->UpdateExListId(NULL);
377       aDrawer->myLists.Clear();
378     }
379   }
380   // Remove Drawers
381   myDrawers.Clear();
382
383   // Release memory
384   myAllocator->Reset();
385   myAllocator->ResetCounters();
386
387   // Remove objects from maps
388   myMapObjects[0].Clear();
389   myMapObjects[1].Clear();
390   myMapObjects[2].Clear();
391   myMapObjects[3].Clear();
392   myMapNonSelectableObjects.Clear();
393   myObjects.Clear();
394 }
395
396 //=======================================================================
397 //function : RebuildViews
398 //purpose  : 
399 //=======================================================================
400
401 void NIS_InteractiveContext::RebuildViews ()
402 {
403   const Handle_NIS_Allocator aNewAlloc = compactObjects();
404
405   // Recalculate all DrawLists in all drawers
406   markAllDrawersUpdated(myDrawers);
407
408   // It is time to destroy the old allocator, not before this line. Because
409   // the old allocator is needed to tidy up draw lists in SetUpdated() calls.
410   if (aNewAlloc.IsNull() == Standard_False)
411     myAllocator = aNewAlloc;
412
413   NCollection_List<Handle_NIS_View>::Iterator anIterV(myViews);
414   for (; anIterV.More(); anIterV.Next()) {
415     const Handle(NIS_View)& aView = anIterV.Value();
416     if (aView.IsNull() == Standard_False)
417       aView->Redraw();
418   }
419 }
420
421 //=======================================================================
422 //function : UpdateViews
423 //purpose  : Only repaint the views refreshing their presentations only for
424 //           those drawers that have been marked as updated.
425 //=======================================================================
426
427 void NIS_InteractiveContext::UpdateViews ()
428 {
429   const Handle_NIS_Allocator aNewAlloc = compactObjects();
430   if (aNewAlloc.IsNull() == Standard_False)
431     myAllocator = aNewAlloc;
432
433   NCollection_List<Handle_NIS_View>::Iterator anIterV(myViews);
434   for (; anIterV.More(); anIterV.Next()) {
435     const Handle(NIS_View)& aView = anIterV.Value();
436     if (aView.IsNull() == Standard_False)
437       aView->Redraw();
438   }
439 }
440
441 //=======================================================================
442 //function : SetSelected
443 //purpose  : 
444 //=======================================================================
445
446 Standard_Boolean NIS_InteractiveContext::SetSelected
447                         (const Handle_NIS_InteractiveObject& theObj,
448                          const Standard_Boolean              isSelected)
449 {
450   Standard_Boolean aResult (Standard_False);
451   if (theObj.IsNull() == Standard_False) {
452     const Standard_Integer anID = theObj->ID();
453     if (isSelected == Standard_False) {
454       if (myMapObjects[NIS_Drawer::Draw_Hilighted].Remove(anID)) {
455         deselectObj (theObj, anID);
456         aResult = Standard_True;
457       }
458     } else {
459       if (IsSelectable(anID) == Standard_True) {
460         if (myMapObjects[NIS_Drawer::Draw_Hilighted].Add(anID)) {
461           selectObj (theObj, anID);
462           aResult = Standard_True;
463         }
464       }
465     }
466   }
467   return aResult;
468 }
469
470 //=======================================================================
471 //function : ProcessSelection
472 //purpose  : 
473 //=======================================================================
474
475 Standard_Boolean NIS_InteractiveContext::ProcessSelection
476                         (const Handle_NIS_InteractiveObject& theObj,
477                          const Standard_Boolean              isMultiple)
478 {
479   Standard_Boolean aResult (Standard_False);
480   Standard_Integer anID (0);
481   Standard_Boolean wasSelected (Standard_False);
482   if (theObj.IsNull() == Standard_False) {
483     const Handle(NIS_Drawer)& aDrawer = theObj->GetDrawer();
484     if (aDrawer.IsNull() == Standard_False) {
485       if (aDrawer->GetContext() == this) {
486         anID = theObj->ID();
487         wasSelected = myMapObjects[NIS_Drawer::Draw_Hilighted].Contains (anID);
488       }
489     }
490   }
491
492   switch (mySelectionMode) {
493   case Mode_Normal:
494   case Mode_Additive:
495     if (isMultiple == Standard_False) {
496       ClearSelected();
497       aResult = Standard_True;
498     } else if (wasSelected && mySelectionMode == Mode_Normal) {
499       myMapObjects[NIS_Drawer::Draw_Hilighted].Remove( anID );
500       deselectObj (theObj, anID);
501       aResult = Standard_True;
502       break;
503     }
504     if (wasSelected == Standard_False && IsSelectable(anID) == Standard_True) {
505       myMapObjects[NIS_Drawer::Draw_Hilighted].Add( anID );
506       selectObj (theObj, anID);
507       aResult = Standard_True;
508     }
509     break;
510   case Mode_Exclusive:
511     if (wasSelected) {
512       myMapObjects[NIS_Drawer::Draw_Hilighted].Remove( anID );
513       deselectObj (theObj, anID);
514       aResult = Standard_True;
515     }
516     break;
517   default: ;
518   }
519   return aResult;
520 }
521
522 //=======================================================================
523 //function : ProcessSelection
524 //purpose  : 
525 //=======================================================================
526
527 void NIS_InteractiveContext::ProcessSelection
528                         (const TColStd_PackedMapOfInteger& mapSel,
529                          const Standard_Boolean            isMultiple)
530 {
531   //subtract non-selectable objects
532   TColStd_PackedMapOfInteger aMap;
533   aMap.Subtraction (mapSel, myMapNonSelectableObjects);
534
535   TColStd_MapIteratorOfPackedMapOfInteger anIter;
536   switch (mySelectionMode) {
537   case Mode_Normal:
538     if (isMultiple == Standard_False) {
539       ClearSelected();
540       myMapObjects[NIS_Drawer::Draw_Hilighted] = aMap;
541       for (anIter.Initialize (aMap); anIter.More(); anIter.Next()) {
542         const Standard_Integer anID = anIter.Key();
543         selectObj (myObjects(anID), anID);
544       }
545     } else {
546       TColStd_PackedMapOfInteger aMapSub;
547       aMapSub.Intersection(aMap, myMapObjects[NIS_Drawer::Draw_Hilighted]);
548       aMap.Subtract (myMapObjects[NIS_Drawer::Draw_Hilighted]);
549       myMapObjects[NIS_Drawer::Draw_Hilighted].Unite (aMap);
550       myMapObjects[NIS_Drawer::Draw_Hilighted].Subtract (aMapSub);
551       for (anIter.Initialize (aMap); anIter.More(); anIter.Next()) {
552         const Standard_Integer anID = anIter.Key();
553         selectObj (myObjects(anID), anID);
554       }
555       for (anIter.Initialize (aMapSub); anIter.More(); anIter.Next()) {
556         const Standard_Integer anID = anIter.Key();
557         deselectObj (myObjects(anID), anID);
558       }
559     }
560     break;
561   case Mode_Additive:
562     aMap.Subtract (myMapObjects[NIS_Drawer::Draw_Hilighted]);
563     myMapObjects[NIS_Drawer::Draw_Hilighted].Unite (aMap);
564     for (anIter.Initialize (aMap); anIter.More(); anIter.Next()) {
565       const Standard_Integer anID = anIter.Key();
566       selectObj (myObjects(anID), anID);
567     }
568     break;
569   case Mode_Exclusive:
570     aMap.Intersect (myMapObjects[NIS_Drawer::Draw_Hilighted]);
571     myMapObjects[NIS_Drawer::Draw_Hilighted].Subtract (aMap);
572     for (anIter.Initialize (aMap); anIter.More(); anIter.Next()) {
573       const Standard_Integer anID = anIter.Key();
574       deselectObj (myObjects(anID), anID);
575     }
576     break;
577   default: ;
578   }
579 }
580
581 //=======================================================================
582 //function : IsSelected
583 //purpose  : 
584 //=======================================================================
585
586 Standard_Boolean NIS_InteractiveContext::IsSelected
587                                 (const Handle_NIS_InteractiveObject& theObj)
588 {
589   Standard_Boolean aResult (Standard_False);
590   if (theObj.IsNull() == Standard_False) {
591     const Standard_Integer anID = theObj->ID();
592     aResult = myMapObjects[NIS_Drawer::Draw_Hilighted].Contains(anID);
593   }
594   return aResult;
595 }
596
597 //=======================================================================
598 //function : ClearSelected
599 //purpose  : 
600 //=======================================================================
601
602 void NIS_InteractiveContext::ClearSelected ()
603 {
604   TColStd_MapIteratorOfPackedMapOfInteger anIter
605     (myMapObjects[NIS_Drawer::Draw_Hilighted]);
606   for (; anIter.More(); anIter.Next()) {
607     const Standard_Integer anID = anIter.Key();
608     deselectObj (myObjects(anID), anID);
609   }
610   myMapObjects[NIS_Drawer::Draw_Hilighted].Clear();
611 }
612
613 //=======================================================================
614 //function : SetSelected
615 //purpose  : 
616 //=======================================================================
617
618 void NIS_InteractiveContext::SetSelected
619                         (const TColStd_PackedMapOfInteger& mapSel,
620                          const Standard_Boolean            isAdded)
621 {
622   //subtract non-selectable objects
623   TColStd_PackedMapOfInteger aMap;
624   aMap.Subtraction (mapSel, myMapNonSelectableObjects);
625
626   if (aMap.IsEmpty() && isAdded == Standard_False)
627     ClearSelected();
628   else {
629     // Deselect objects
630     TColStd_MapIteratorOfPackedMapOfInteger anIter;
631     if (isAdded == Standard_False) {
632       TColStd_PackedMapOfInteger aMapSub;
633       aMapSub.Subtraction (myMapObjects[NIS_Drawer::Draw_Hilighted], aMap);
634       for (anIter.Initialize(aMapSub); anIter.More(); anIter.Next()) {
635         const Standard_Integer anID = anIter.Key();
636         deselectObj (myObjects(anID), anID);
637       }
638       myMapObjects[NIS_Drawer::Draw_Hilighted].Subtract(aMapSub);
639     }
640     aMap.Subtract (myMapObjects[NIS_Drawer::Draw_Hilighted]);
641     myMapObjects[NIS_Drawer::Draw_Hilighted].Unite (aMap);
642
643     // Select objects
644     for (anIter.Initialize (aMap); anIter.More(); anIter.Next()) {
645       const Standard_Integer anID = anIter.Key();
646       selectObj (myObjects(anID), anID);
647     }
648   }
649 }
650
651 //=======================================================================
652 //function : selectObject
653 //purpose  : 
654 //=======================================================================
655
656 Standard_Real NIS_InteractiveContext::selectObject
657                                 (Handle_NIS_InteractiveObject&  theSel,
658                                  NCollection_List<DetectedEnt>& theDetected,
659                                  const gp_Ax1&                  theAxis,
660                                  const Standard_Real            theOver,
661                                  const Standard_Boolean         isOnlySel) const
662 {
663   static const Standard_Real anInfiniteDist = 0.5 * RealLast();
664   Standard_Real aMinDist(anInfiniteDist);
665   if (mySelectionMode != Mode_NoSelection || isOnlySel == Standard_False)
666   {
667     DetectedEnt anEnt;
668     NCollection_SparseArray <Handle_NIS_InteractiveObject>::ConstIterator
669       anIter(myObjects);
670     for (; anIter.More(); anIter.Next()) {
671       const Handle(NIS_InteractiveObject)& anObj = anIter.Value();
672       if (anObj.IsNull() == Standard_False)
673         if (anObj->IsDisplayed() &&
674             (!myMapNonSelectableObjects.Contains (anObj->ID()) ||
675              isOnlySel == Standard_False))
676         {
677           // Pass the object through the SelectFilter if available
678           if (mySelectFilter.IsNull() == Standard_False)
679             if (mySelectFilter->IsOk (anObj.operator->()) == Standard_False)
680               continue;
681           // Check the intersection with the box
682           const Bnd_B3f& aBox = anObj->GetBox();
683           if (aBox.IsOut (theAxis, Standard_False, theOver) == Standard_False)
684           {
685             anEnt.Dist = anObj->Intersect (theAxis, theOver);
686             if (anEnt.Dist < anInfiniteDist) {
687               anEnt.PObj = anObj.operator->();
688               // Insert the detected entity in the sorted list
689               NCollection_List<DetectedEnt>::Iterator anIterD(theDetected);
690               for (; anIterD.More(); anIterD.Next()) {
691                 if (anEnt.Dist < anIterD.Value().Dist) {
692                   theDetected.InsertBefore(anEnt, anIterD);
693                   break;
694                 }
695               }
696               if (anIterD.More() == Standard_False)
697                 theDetected.Append(anEnt);
698               if (anEnt.Dist < aMinDist) {
699                 aMinDist = anEnt.Dist;
700                 theSel = anObj;
701               }
702             }
703           }
704         }
705     }
706   }
707   return aMinDist;
708 }
709
710 //=======================================================================
711 //function : SetSelectable
712 //purpose  : 
713 //=======================================================================
714
715 void NIS_InteractiveContext::SetSelectable 
716                         (const TColStd_PackedMapOfInteger& objIDs,
717                          const Standard_Boolean            isSelectable)
718 {
719   if (isSelectable) { // subtract given IDs from myMapNonSelectableObjects
720     myMapNonSelectableObjects.Subtract(objIDs);
721   }
722   else {              // deselect IDs, add them to myMapNonSelectableObjects
723     Standard_Integer anID;
724     TColStd_MapIteratorOfPackedMapOfInteger anIter(objIDs);
725     for (; anIter.More(); anIter.Next()) {
726       anID = anIter.Key();
727       if ( myMapObjects[NIS_Drawer::Draw_Hilighted].Contains(anID)) {
728         myMapObjects[NIS_Drawer::Draw_Hilighted].Remove(anID);
729         deselectObj (myObjects(anID), anID);
730       }
731     }
732     myMapNonSelectableObjects.Unite(objIDs);
733   }
734 }
735
736 //=======================================================================
737 //function : selectObjects
738 //purpose  : 
739 //=======================================================================
740
741 Standard_Boolean NIS_InteractiveContext::selectObjects
742                         (TColStd_PackedMapOfInteger& mapObj,
743                          const Bnd_B3f&              theBox,
744                          const gp_Trsf&              theTrf,
745                          const gp_Trsf&              theTrfInv,
746                          const Standard_Boolean      isFullyIncluded) const
747 {
748   Standard_Boolean aResult (Standard_False);
749   if (mySelectionMode != Mode_NoSelection) {
750     NCollection_SparseArray <Handle_NIS_InteractiveObject>::ConstIterator
751       anIter(myObjects);
752     for (; anIter.More(); anIter.Next()) {
753       const Handle(NIS_InteractiveObject)& anObj = anIter.Value();
754       if (anObj.IsNull() == Standard_False)
755         if (anObj->IsDisplayed()) {
756           // Pass the object through the SelectFilter if available
757           if (mySelectFilter.IsNull() == Standard_False)
758             if (mySelectFilter->IsOk (anObj.operator->()) == Standard_False)
759               continue;
760           // Check the intersection with the box
761           const Bnd_B3f& aBox = anObj->GetBox();
762           if (aBox.IsIn (theBox, theTrf)) {
763             mapObj.Add (anObj->ID());
764             aResult = Standard_True;
765           } else if (aBox.IsOut (theBox, theTrf) == Standard_False)
766             if (anObj->Intersect (theBox, theTrfInv, isFullyIncluded))
767             {
768               mapObj.Add (anObj->ID());
769               aResult = Standard_True;
770             }
771         }
772     }
773   }
774   return aResult;
775 }
776
777 //=======================================================================
778 //function : selectObjects
779 //purpose  : 
780 //=======================================================================
781
782 Standard_Boolean NIS_InteractiveContext::selectObjects
783                           (TColStd_PackedMapOfInteger    &mapObj,
784                            const NCollection_List<gp_XY> &thePolygon,
785                            const Bnd_B2f                 &thePolygonBox,
786                            const gp_Trsf                 &theTrfInv,
787                            const Standard_Boolean         isFullyIn) const
788 {
789   Standard_Boolean aResult (Standard_False);
790
791   if (mySelectionMode != Mode_NoSelection) {
792     NCollection_SparseArray <Handle_NIS_InteractiveObject>::ConstIterator
793       anIter(myObjects);
794
795     for (; anIter.More(); anIter.Next()) {
796       const Handle(NIS_InteractiveObject)& anObj = anIter.Value();
797
798       if (anObj.IsNull() == Standard_False)
799         if (anObj->IsDisplayed()) {
800           // Pass the object through the SelectFilter if available
801           if (mySelectFilter.IsNull() == Standard_False)
802             if (mySelectFilter->IsOk (anObj.operator->()) == Standard_False)
803               continue;
804
805           // Comvert 3d box to 2d one
806           const Bnd_B3f    &aBox = anObj->GetBox();
807           Bnd_B2f           aB2d;
808           Standard_Real     aX[2];
809           Standard_Real     aY[2];
810           Standard_Real     aZ[2];
811           gp_XYZ            aBoxVtx;
812           Standard_Integer  i;
813
814           aBox.CornerMin().Coord(aX[0], aY[0], aZ[0]);
815           aBox.CornerMax().Coord(aX[1], aY[1], aZ[1]);
816
817           for (i = 0; i < 8; i++) {
818             aBoxVtx.SetX(aX[(i & 1) ? 1 : 0]);
819             aBoxVtx.SetY(aY[(i & 2) ? 1 : 0]);
820             aBoxVtx.SetZ(aZ[(i & 4) ? 1 : 0]);
821             theTrfInv.Transforms(aBoxVtx);
822             aB2d.Add(gp_XY(aBoxVtx.X(), aBoxVtx.Y()));
823           }
824
825           // Check the intersection with the box
826           if (thePolygonBox.IsOut(aB2d) == Standard_False) {
827             if (anObj->Intersect(thePolygon, theTrfInv, isFullyIn)) {
828               mapObj.Add (anObj->ID());
829               aResult = Standard_True;
830             }
831           }
832         }
833     }
834   }
835   return aResult;
836 }
837
838 //=======================================================================
839 //function : deselectObj
840 //purpose  : 
841 //=======================================================================
842
843 void NIS_InteractiveContext::deselectObj
844                         (const Handle(NIS_InteractiveObject)& theObj,
845                          const Standard_Integer               theID)
846 {
847   if (theObj.IsNull() == Standard_False) {
848     const Handle(NIS_Drawer)& aDrawer = theObj->GetDrawer();
849     if (theObj->IsTransparent()) {
850       myMapObjects[NIS_Drawer::Draw_Transparent].Add(theID);
851       aDrawer->SetUpdated(NIS_Drawer::Draw_Transparent);
852     } else if (theObj->myBaseType == NIS_Drawer::Draw_Top) {
853       myMapObjects[NIS_Drawer::Draw_Top].Add(theID);
854       aDrawer->SetUpdated(NIS_Drawer::Draw_Top);
855     } else {
856       myMapObjects[NIS_Drawer::Draw_Normal].Add(theID);
857       aDrawer->SetUpdated(NIS_Drawer::Draw_Normal);
858     }
859     aDrawer->SetUpdated(NIS_Drawer::Draw_Hilighted);
860     theObj->myDrawType = theObj->myBaseType;
861   }
862 }
863
864 //=======================================================================
865 //function : selectObj
866 //purpose  : 
867 //=======================================================================
868
869 void NIS_InteractiveContext::selectObj
870                         (const Handle(NIS_InteractiveObject)& theObj,
871                          const Standard_Integer               theID)
872 {
873   if (theObj.IsNull() == Standard_False) {
874     const Handle(NIS_Drawer)& aDrawer = theObj->GetDrawer();
875     if (theObj->IsTransparent()) {
876       myMapObjects[NIS_Drawer::Draw_Transparent].Remove(theID);
877       aDrawer->SetUpdated(NIS_Drawer::Draw_Transparent);
878     } else if (theObj->myDrawType == NIS_Drawer::Draw_Top) {
879       myMapObjects[NIS_Drawer::Draw_Top].Remove(theID);
880       aDrawer->SetUpdated(NIS_Drawer::Draw_Top);
881     } else {
882       myMapObjects[NIS_Drawer::Draw_Normal].Remove(theID);
883       aDrawer->SetUpdated(NIS_Drawer::Draw_Normal);
884     }
885     aDrawer->SetUpdated(NIS_Drawer::Draw_Hilighted);
886     theObj->myDrawType = NIS_Drawer::Draw_Hilighted;
887   }
888 }
889
890 //=======================================================================
891 //function : drawerForDisplay
892 //purpose  : 
893 //=======================================================================
894
895 const Handle_NIS_Drawer& NIS_InteractiveContext::drawerForDisplay
896                                 (const Handle_NIS_InteractiveObject& theObj,
897                                  const Handle_NIS_Drawer&            theDrawer)
898 {
899   Handle(NIS_Drawer) aDrawer;
900   if (theDrawer.IsNull() == Standard_False) {
901     if (theDrawer->myCtx != this)
902       Standard_NoSuchObject::Raise ("NIS_InteractiveContext::Display (0)");
903     aDrawer = theDrawer;
904   } else {
905     const Handle(NIS_Drawer)& anObjDrawer = theObj->GetDrawer();
906     if (anObjDrawer.IsNull() == Standard_False)
907       return anObjDrawer;
908     aDrawer = theObj->DefaultDrawer(0L);
909     aDrawer->myCtx = this;
910   }
911   return theObj->SetDrawer (aDrawer, Standard_False);
912 }
913
914 //=======================================================================
915 //function : objectIdForDisplay
916 //purpose  : 
917 //=======================================================================
918
919 void NIS_InteractiveContext::objectForDisplay
920                                 (Handle_NIS_InteractiveObject& theObj,
921                                  const NIS_Drawer::DrawType    theDrawType)
922 {
923   if (theObj->ID() == 0) {
924     // Create a new ID for this object
925     Handle(NIS_InteractiveObject) anObj;
926     theObj->Clone(myAllocator, anObj);
927     theObj = anObj;
928     anObj->myID = ++myLastObjectId;
929     myObjects.SetValue (myLastObjectId, anObj);
930     myMapObjects[theDrawType].Add(anObj->myID);
931     anObj->myDrawType = theDrawType;
932   }
933 }
934
935 //=======================================================================
936 //function : compactObjects
937 //purpose  : 
938 //=======================================================================
939
940 Handle_NIS_Allocator NIS_InteractiveContext::compactObjects()
941 {
942   Handle(NIS_Allocator) aNewAlloc;
943
944   NCollection_List<Handle_NIS_View>::Iterator anIterV;
945   // Check if the memory used by objects has to be compacted.
946   const Standard_Size nAllocated = myAllocator->NAllocated();
947
948   if (nAllocated > 1024*1024) {
949     const Standard_Size nFreed = myAllocator->NFreed();
950     if ((nFreed * 5) / 3 > nAllocated || nFreed > 20*1024*1024)
951     {
952       for (anIterV.Init(myViews); anIterV.More(); anIterV.Next()) {
953         const Handle(NIS_View)& aView = anIterV.Value();
954         if (aView.IsNull() == Standard_False) {
955           aView->myDynHilighted.Nullify();
956           aView->GetDetected().Clear();
957         }
958       }
959       // Compact the memory: clone all objects to a new allocator, release
960       // the old allocator instance.
961       aNewAlloc = new NIS_Allocator;
962       NCollection_SparseArray<Handle_NIS_InteractiveObject>::Iterator
963         anIter(myObjects);
964       for (; anIter.More(); anIter.Next()) {
965         if (anIter.Value().IsNull() == Standard_False) {
966           Handle(NIS_InteractiveObject)& aNewObj = anIter.ChangeValue();
967           const Handle(NIS_InteractiveObject) anObj = aNewObj;
968           aNewObj.Nullify();
969           anObj->CloneWithID(aNewAlloc, aNewObj);
970         }
971       }
972     }
973   }
974   return aNewAlloc;
975 }
976
977 //=======================================================================
978 //function : markAllDrawersUpdated
979 //purpose  : 
980 //=======================================================================
981
982 void markAllDrawersUpdated (const NCollection_Map<Handle_NIS_Drawer>& lstDrv)
983 {
984   NCollection_Map<Handle_NIS_Drawer>::Iterator anIterD (lstDrv);
985   for (; anIterD.More(); anIterD.Next()) {
986     const Handle(NIS_Drawer)& aDrawer = anIterD.Value();
987     if (aDrawer.IsNull() == Standard_False) {
988       aDrawer->SetUpdated (NIS_Drawer::Draw_Normal,
989                            NIS_Drawer::Draw_Top,
990                            NIS_Drawer::Draw_Transparent,
991                            NIS_Drawer::Draw_Hilighted);
992     }
993   }
994 }