0024530: TKMesh - remove unused package IntPoly
[occt.git] / src / NIS / NIS_View.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
8 // under the terms of the GNU Lesser General Public 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_View.hxx>
17 #include <NIS_InteractiveContext.hxx>
18 #include <NIS_InteractiveObject.hxx>
19 #include <gp_Ax1.hxx>
20 #include <Visual3d_View.hxx>
21 #include <Bnd_B2f.hxx>
22 #include <TColStd_MapIteratorOfPackedMapOfInteger.hxx>
23
24 #include <OpenGl_GlCore11.hxx>
25
26 IMPLEMENT_STANDARD_HANDLE  (NIS_View, V3d_View)
27 IMPLEMENT_STANDARD_RTTIEXT (NIS_View, V3d_View)
28
29 //=======================================================================
30 //function : NIS_View()
31 //purpose  : Constructor
32 //=======================================================================
33
34 NIS_View::NIS_View (const Handle(V3d_Viewer)&    theViewer,
35                     const Handle(Aspect_Window)& theWindow)
36   : V3d_View (theViewer),
37     myIsTopHilight(Standard_False),
38     myDoHilightSelected(Standard_True)
39 {
40   if (!theWindow.IsNull())
41     V3d_View::SetWindow (theWindow, NULL, &MyCallback, this);
42 }
43
44 //=======================================================================
45 //function : SetWindow
46 //purpose  :
47 //=======================================================================
48
49 void NIS_View::SetWindow(const Handle(Aspect_Window) &theWindow)
50 {
51   V3d_View::SetWindow (theWindow, NULL, &MyCallback, this);
52 }
53
54 // //=======================================================================
55 // //function : ~NIS_View
56 // //purpose  : Destructor
57 // //=======================================================================
58
59 // NIS_View::~NIS_View()
60 // {}
61
62
63 //=======================================================================
64 //function : AddContext
65 //purpose  :
66 //=======================================================================
67
68 void  NIS_View::AddContext (NIS_InteractiveContext * theCtx)
69 {
70   // Check that the given context is not among already attached contexts
71   NCollection_List<NIS_InteractiveContext *>::Iterator anIter (myContexts);
72   for (; anIter.More(); anIter.Next())
73     if (anIter.Value() == theCtx)
74       break;
75   if (anIter.More() == Standard_False)
76     myContexts.Append (theCtx);
77 }
78
79 //=======================================================================
80 //function : RemoveContext
81 //purpose  :
82 //=======================================================================
83
84 void NIS_View::RemoveContext (NIS_InteractiveContext * theCtx)
85 {
86   NCollection_List<NIS_InteractiveContext *>::Iterator anIter (myContexts);
87   for (; anIter.More(); anIter.Next())
88     if (anIter.Value() == theCtx) {
89       myContexts.Remove (anIter);
90       break;
91     }
92
93   NCollection_Map<Handle_NIS_Drawer>::Iterator anIterD (theCtx->GetDrawers ());
94   for (; anIterD.More(); anIterD.Next()) {
95     const Handle(NIS_Drawer)& aDrawer = anIterD.Value();
96     if (aDrawer.IsNull() == Standard_False) {
97       aDrawer->UpdateExListId(this);
98     }
99   }
100 }
101
102 //=======================================================================
103 //function : FitAll3d
104 //purpose  :
105 //=======================================================================
106
107 Standard_Boolean NIS_View::FitAll3d (const Quantity_Coefficient theCoef)
108 {
109   Standard_Boolean aResult(Standard_False);
110
111   Bnd_B3f aBox = GetBndBox();
112
113   // Check that the box is not empty
114   if (aBox.IsVoid() == Standard_False && MyView->IsDefined() == Standard_True)
115   {
116     // Convert the 3D box to 2D representation in view coordinates
117     gp_XYZ aCoord;
118
119     const gp_XYZ aCorner[2] = { aBox.CornerMin(), aBox.CornerMax() };
120
121     // Fit depth
122     const gp_XYZ& aBMin = aCorner[0];
123     const gp_XYZ& aBMax = aCorner[1];
124
125     gp_Pnt anAABBCenter ((aBMin.X() + aBMax.X()) * 0.5,
126                          (aBMin.Y() + aBMax.Y()) * 0.5,
127                          (aBMin.Z() + aBMax.Z()) * 0.5);
128
129     gp_Vec aCenter2AABB (myCamera->Center(), anAABBCenter);
130     gp_Dir aDir = myCamera->Direction();
131
132     // distance projection onto camera direction
133     Standard_Real aDistToBox = -aCenter2AABB.Dot (aDir);
134     gp_Vec aZShift = gp_Vec (aDir).Reversed().Scaled (aDistToBox);
135
136     gp_Pnt anEyeBefore   = myCamera->Eye();
137     gp_Pnt aCenterBefore = myCamera->Center();
138
139     myCamera->BeginUpdate();
140     myCamera->SetEye (myCamera->Eye().Translated (aZShift));
141     myCamera->SetCenter (myCamera->Center().Translated (aZShift));
142     myCamera->EndUpdate();
143
144     Standard_Real Umin = RealLast();
145     Standard_Real Umax = RealFirst();
146     Standard_Real Vmin = RealLast();
147     Standard_Real Vmax = RealFirst();
148     Standard_Real U, V, W;
149
150     Standard_Boolean doFit = Standard_True;
151     while (doFit) 
152     {
153       for (Standard_Integer i = 0; i < 8; i++) {
154         if (i & 0x1) aCoord.SetX (aCorner[0].X());
155         else         aCoord.SetX (aCorner[1].X());
156         if (i & 0x2) aCoord.SetY (aCorner[0].Y());
157         else         aCoord.SetY (aCorner[1].Y());
158         if (i & 0x4) aCoord.SetZ (aCorner[0].Z());
159         else         aCoord.SetZ (aCorner[1].Z());
160
161         MyView->Projects(aCoord.X(), aCoord.Y(), aCoord.Z(), U, V, W);
162         if (i) {
163           Umin = Min(Umin, U); Umax = Max(Umax, U);
164           Vmin = Min(Vmin, V); Vmax = Max(Vmax, V);
165         }
166         else {
167           Umin = Umax = U;
168           Vmin = Vmax = V;
169         }
170       }
171
172       if ( (Umax > Umin) && (Vmax > Vmin) )
173       {
174         gp_Pnt ViewDims = myCamera->ViewDimensions();
175         Standard_Real DxvOld = ViewDims.X();
176
177         Standard_Real Xrp, Yrp, DxvNew, DyvNew;
178
179         DxvNew = Abs(Umax - Umin); DyvNew = Abs(Vmax - Vmin);
180         DxvNew *= (1. + theCoef);
181         DyvNew *= (1. + theCoef);
182
183         Standard_Real aRatio = DxvNew / DxvOld;
184
185         Xrp = (Umin + Umax)/2. ; Yrp = (Vmin + Vmax)/2. ;
186         Umin = Xrp - DxvNew/2. ; Umax = Xrp + DxvNew/2. ;
187         Vmin = Yrp - DyvNew/2. ; Vmax = Yrp + DyvNew/2. ;
188
189         // fit view
190         FitAll (Umin, Vmin, Umax, Vmax);
191
192         // ratio 1e+6 often gives calculation error(s), reduce it
193         // if (aRatio < 1e+6) doFit = Standard_False;
194         if (aRatio < 100)
195         {
196           doFit = Standard_False;
197         }
198
199         aResult = Standard_True;
200       }
201       else
202       {
203         doFit = Standard_False;
204       }
205     }
206
207     if (!aResult)
208     {
209       myCamera->BeginUpdate();
210       myCamera->SetCenter (aCenterBefore);
211       myCamera->SetEye (anEyeBefore);
212       myCamera->EndUpdate();
213     }
214   }
215
216   return aResult;
217 }
218
219 //=======================================================================
220 //function : GetBndBox
221 //purpose  :
222 //=======================================================================
223
224 Bnd_B3f NIS_View::GetBndBox() const
225 {
226   // Calculate the 3D bounding box of visible objects
227   // in all interactive contexts
228   Bnd_B3f aBox;
229   NCollection_List<NIS_InteractiveContext *>::Iterator anIterC (myContexts);
230   for (; anIterC.More(); anIterC.Next()) {
231     NCollection_Map<Handle_NIS_Drawer>::Iterator anIterD
232       (anIterC.Value()->myDrawers);
233     for (; anIterD.More(); anIterD.Next()) {
234       const Handle(NIS_Drawer)& aDrawer = anIterD.Value();
235       Bnd_B3f aBoxD = aDrawer->GetBox (this);
236       aBox.Add (aBoxD);
237     }
238   }
239
240   // Take the bounding box of AIS objects displayed in the view
241   Standard_Real aVal[6];
242   View()->MinMaxValues(aVal[0], aVal[1], aVal[2], aVal[3], aVal[4], aVal[5]);
243   if (aVal[3] < 0.5 * RealLast()) {
244     aBox.Add (gp_XYZ (aVal[0], aVal[1], aVal[2]));
245     aBox.Add (gp_XYZ (aVal[3], aVal[4], aVal[5]));
246   }
247
248   return aBox;
249 }
250
251 //=======================================================================
252 //function : GetBndBox
253 //purpose  :
254 //=======================================================================
255
256 void NIS_View::GetBndBox( Standard_Integer& theXMin, Standard_Integer& theXMax,
257                           Standard_Integer& theYMin, Standard_Integer& theYMax ) const
258 {
259   theXMin = theYMin = 0;
260   theXMax = theYMax = -1;
261
262   Bnd_B3f aBox = GetBndBox();
263
264   // Check that the box is not empty
265   if (aBox.IsVoid() == Standard_False) {
266     // Convert the 3D box to 2D representation in pixel coordinates
267     gp_XYZ aCoord;
268     Standard_Integer anXp, anYp;
269     const gp_XYZ aCorner[2] = { aBox.CornerMin(), aBox.CornerMax() };
270     Standard_Integer aLimp[4] = { 1000000, -1000000, 1000000, -1000000 };
271     for (Standard_Integer i = 0; i < 8; i++) {
272       if (i & 0x1) aCoord.SetX (aCorner[0].X());
273       else         aCoord.SetX (aCorner[1].X());
274       if (i & 0x2) aCoord.SetY (aCorner[0].Y());
275       else         aCoord.SetY (aCorner[1].Y());
276       if (i & 0x4) aCoord.SetZ (aCorner[0].Z());
277       else         aCoord.SetZ (aCorner[1].Z());
278       Convert( aCoord.X(), aCoord.Y(), aCoord.Z(), anXp, anYp );
279       if (aLimp[0] > anXp) aLimp[0] = anXp;
280       if (aLimp[1] < anXp) aLimp[1] = anXp;
281       if (aLimp[2] > anYp) aLimp[2] = anYp;
282       if (aLimp[3] < anYp) aLimp[3] = anYp;
283     }
284     if (aLimp[0] < aLimp[1] && aLimp[2] < aLimp[3])
285     {
286       // Scale the view
287       // WindowFit (aLimp[0], aLimp[2], aLimp[1], aLimp[3]);
288       theXMin = aLimp[0];
289       theXMax = aLimp[1];
290       theYMin = aLimp[2];
291       theYMax = aLimp[3];
292     }
293   }
294 }
295
296
297 //=======================================================================
298 //function : MyCallback
299 //purpose  :
300 //=======================================================================
301
302 int NIS_View::MyCallback (Aspect_Drawable                /* Window ID */,
303                           void*                          ptrData,
304                           Aspect_GraphicCallbackStruct*  callData /* call data */)
305 {
306   // Avoid multiple rendering of the scene ( accordingly with update of
307   // callback mechanism, that invokes additional callbacks before
308   // underlay and overlay redrawing with OCC_PRE_REDRAW and OCC_PRE_OVERLAY
309   // bits added to the "reason" value of the callback data structure;
310   // see comments to OCC_REDRAW_ADDITIONAL_CALLBACKS definition )
311   if (callData->reason & OCC_REDRAW_ADDITIONAL_CALLBACKS)
312     return 0;
313
314   const Handle(NIS_View) thisView (static_cast<NIS_View *> (ptrData));
315   NCollection_List<NIS_InteractiveContext *>::Iterator anIter;
316 #ifdef CLIP
317   // Find the bounding box of all displayed objects by summing the boxes stored
318   // in the relevant DrawList instances.
319   Bnd_B3f aBndBox;
320   for (anIter = thisView->myContexts; anIter.More(); anIter.Next())
321     anIter.Value()->GetBox (aBndBox, pView);
322
323   if (aBndBox.IsVoid() == Standard_False) {
324     const gp_XYZ aBoxSize   = 0.5 * (aBndBox.CornerMax() - aBndBox.CornerMin());
325     const gp_XYZ aBoxCenter = 0.5 * (aBndBox.CornerMax() + aBndBox.CornerMin());
326
327     // Find the ray passing through the clicked point in the view window.
328     Standard_Real anX, anY, aZ;
329     thisView->Convert(0, 0, anX, anY, aZ);  // 3D point for the 3D coordinates
330     const gp_Pnt anEye (anX, anY, aZ);
331     thisView->Proj (anX, anY, aZ);  // vector orthogonal to the view plane
332     const gp_Dir aProj (anX, anY, aZ);
333     const gp_Ax1 anAxis (anEye, aProj);
334
335     const Standard_Real aCenterDist = (anEye.XYZ() - aBoxCenter) * aProj.XYZ();
336     const Standard_Real aBoxExtent /*(fabs(aBoxSize.X() * anX) +
337                                     fabs(aBoxSize.Y() * anY) +
338                                     fabs(aBoxSize.Z() * aZ))*/(100.);
339
340 #define FRONT_CLIPPING_PLANE (GL_CLIP_PLANE0 + 0)
341 #define BACK_CLIPPING_PLANE  (GL_CLIP_PLANE0 + 1)
342     Standard_Real arr[4] = {
343       0.0,  /* Nx */
344       0.0,  /* Ny */
345       1.0,  /* Nz */
346       0.
347     };
348     arr[3] = aBoxExtent + 1.;
349     glClipPlane (BACK_CLIPPING_PLANE, arr);
350     glEnable (BACK_CLIPPING_PLANE);
351     arr[2] = -1.0;
352     arr[3] = aBoxExtent + 1.;
353     glClipPlane (FRONT_CLIPPING_PLANE, arr);
354     glEnable (FRONT_CLIPPING_PLANE);
355   }
356 #endif //IS_DISABLED
357
358   GLboolean isDepthWriteMask, isDepthTest;
359   glGetBooleanv(GL_DEPTH_WRITEMASK,&isDepthWriteMask);
360   glGetBooleanv(GL_DEPTH_TEST,&isDepthTest);
361 //   printf ("GlDepthMask=%d; GlDepthTest=%d\n", depthwritemask, depthtest);
362   glDisableClientState(GL_COLOR_ARRAY);
363   glDisableClientState(GL_EDGE_FLAG_ARRAY);
364   glDisableClientState(GL_INDEX_ARRAY);
365   glDisableClientState(GL_NORMAL_ARRAY);
366   glDisableClientState(GL_TEXTURE_COORD_ARRAY);
367   if (!isDepthTest) {
368     glEnable(GL_DEPTH_TEST);
369     glDepthFunc(GL_LESS);
370     glClearDepth(1.);
371     glClear(GL_DEPTH_BUFFER_BIT);
372   }
373
374   TColStd_MapIteratorOfPackedMapOfInteger anIterM(thisView->myExListId);
375   for (; anIterM.More(); anIterM.Next())
376     if (anIterM.Key() != 0) {
377 #ifdef ARRAY_LISTS
378       glDeleteLists (anIterM.Key(), 5);
379 #else
380       glDeleteLists (anIterM.Key(), 1);
381     }
382 #endif
383   thisView->myExListId.Clear();
384
385   for (anIter = thisView->myContexts; anIter.More(); anIter.Next())
386     anIter.Value()->redraw (thisView, NIS_Drawer::Draw_Normal);
387
388   // #818151 - selected object is hidden by covered unselected one
389   // display hilighted objects always above the rest ones
390   if (thisView->myIsTopHilight == Standard_True) {
391     glDepthFunc(GL_ALWAYS);
392   }
393
394   for (anIter = thisView->myContexts; anIter.More(); anIter.Next())
395     anIter.Value()->redraw (thisView, NIS_Drawer::Draw_Hilighted);
396   for (anIter = thisView->myContexts; anIter.More(); anIter.Next())
397     anIter.Value()->redraw (thisView, NIS_Drawer::Draw_DynHilighted);
398   for (anIter = thisView->myContexts; anIter.More(); anIter.Next())
399     anIter.Value()->redraw (thisView, NIS_Drawer::Draw_Transparent);
400
401   // draw top objects always above
402   if (thisView->myIsTopHilight == Standard_False) {
403     glDepthFunc(GL_ALWAYS);
404   }
405
406   for (anIter = thisView->myContexts; anIter.More(); anIter.Next())
407     anIter.Value()->redraw (thisView, NIS_Drawer::Draw_Top);
408
409   return 0;
410 }
411
412 //=======================================================================
413 //function : DynamicHilight
414 //purpose  :
415 //=======================================================================
416
417 void NIS_View::DynamicHilight  (const Standard_Integer theX,
418                                 const Standard_Integer theY)
419 {
420   myDetected.Clear();
421   const Handle(NIS_InteractiveObject) aSelected = Pick (theX, theY);
422
423   // ASV: if at least one Context returns IsSelectable()==False,
424   // hilight is canceled, this method returns
425   if (aSelected.IsNull() == Standard_False) {
426     if (aSelected->IsSelectable() == Standard_False)
427       return;
428   }
429   if (aSelected != myDynHilighted) {
430     const Handle(NIS_View) aView (this);
431     if (myDynHilighted.IsNull() == Standard_False)
432       if (myDynHilighted->GetDrawer().IsNull() == Standard_False)
433         myDynHilighted->GetDrawer()->SetDynamicHilighted(Standard_False,
434                                                          myDynHilighted, aView);
435
436     // 30.07.10 - NKV - synchronize behaviour with AIS interactive context (if need)
437     if (aSelected.IsNull() ||
438         (myDoHilightSelected == Standard_False &&
439          aSelected->GetDrawer()->GetContext()->IsSelected(aSelected)))
440     {
441       myDynHilighted.Nullify();
442     }
443     else {
444       aSelected->GetDrawer()->SetDynamicHilighted (Standard_True,
445                                                    aSelected, aView);
446       myDynHilighted = aSelected;
447     }
448     Redraw();
449   }
450 }
451
452 //=======================================================================
453 //function : DynamicUnhilight
454 //purpose  :
455 //=======================================================================
456
457 void NIS_View::DynamicUnhilight(const Handle_NIS_InteractiveObject& theObj)
458 {
459   if (theObj == myDynHilighted && theObj.IsNull() == Standard_False) {
460     const Handle(NIS_View) aView (this);
461     if (myDynHilighted->GetDrawer().IsNull() == Standard_False)
462       myDynHilighted->GetDrawer()->SetDynamicHilighted (Standard_False,
463                                                         myDynHilighted, aView);
464     myDynHilighted.Nullify();
465     Redraw();
466   }
467 }
468
469 //=======================================================================
470 //function : Select
471 //purpose  : selection by single click
472 //=======================================================================
473
474 void NIS_View::Select (const Standard_Integer theX,
475                        const Standard_Integer theY,
476                        const Standard_Boolean isForceMultiple,
477                        const Standard_Boolean theRedraw)
478 {
479   myDetected.Clear();
480   const Handle(NIS_InteractiveObject) aSelected = Pick (theX, theY);
481   NCollection_List<NIS_InteractiveContext *>::Iterator anIter (myContexts);
482   for (; anIter.More(); anIter.Next())
483     anIter.Value()->ProcessSelection (aSelected, isForceMultiple);
484   if (aSelected == myDynHilighted && aSelected.IsNull() == Standard_False)
485   {
486     myDynHilighted.Nullify();
487     const Handle(NIS_Drawer)& aDrawer = aSelected->GetDrawer();
488     aDrawer->SetDynamicHilighted (Standard_False, aSelected, this);
489   }
490   if (theRedraw) Redraw();
491 }
492
493 //=======================================================================
494 //function : Select
495 //purpose  : selection by rectange
496 //=======================================================================
497
498 void NIS_View::Select (const Standard_Integer  theXmin,
499                        const Standard_Integer  theYmin,
500                        const Standard_Integer  theXmax,
501                        const Standard_Integer  theYmax,
502                        const Standard_Boolean  isForceMult,
503                        const Standard_Boolean  isFullyIncluded,
504                        const Standard_Boolean  theRedraw)
505 {
506   myDetected.Clear();
507   Standard_Real anX, anY, aZ;
508   if (theXmin == theXmax || theYmin == theYmax)
509     return;
510
511   //Transformed box corresponding to the selected rectangle
512   Proj (anX, anY, aZ);                  // vector orthogonal to the view plane
513   const gp_Dir aProj (anX, anY, aZ);
514
515   Convert(theXmin, theYmin, anX, anY, aZ); // 3D point for the 3D coordinates
516   const gp_Pnt anEye (anX, anY, aZ);
517
518   Convert(theXmax, theYmin, anX, anY, aZ); // 3D point for the 3D coordinates
519   const gp_XYZ anXdir (gp_XYZ(anX, anY, aZ) - anEye.XYZ());
520   const gp_Ax3 anAx3 (anEye, aProj, anXdir);
521   gp_Trsf aTrf;
522   aTrf.SetTransformation (anAx3);
523   const gp_Trsf aTrfInv = aTrf.Inverted();
524
525   Convert(theXmax, theYmax, anX, anY, aZ); // 3D point for the 3D coordinates
526   gp_XYZ anUpperCorner (anX, anY, aZ);
527   aTrf.Transforms(anUpperCorner);
528
529   // Selecting box
530   Bnd_B3f aBoxSel;
531   aBoxSel.Add (gp_XYZ(0., 0., -10000.));
532   aBoxSel.Add (anUpperCorner);
533
534   TColStd_PackedMapOfInteger mapSelected;
535   NCollection_List<NIS_InteractiveContext *>::Iterator anIterC (myContexts);
536   for (; anIterC.More(); anIterC.Next()) {
537     NIS_InteractiveContext * pCtx = anIterC.Value();
538     mapSelected.Clear();
539     pCtx->selectObjects (mapSelected, aBoxSel, aTrfInv, aTrf, isFullyIncluded);
540     pCtx->ProcessSelection (mapSelected, isForceMult);
541   }
542   if (theRedraw) Redraw();
543 }
544
545 //=======================================================================
546 //function : Select
547 //purpose  : Selection by polygon
548 //=======================================================================
549
550 void  NIS_View::Select (const NCollection_List<gp_XY> &thePolygon,
551                         const Standard_Boolean         isForceMult,
552                         const Standard_Boolean         isFullyIncluded,
553                         const Standard_Boolean         theRedraw)
554 {
555   myDetected.Clear();
556   if (thePolygon.IsEmpty())
557     return;
558
559   Standard_Real anX, anY, aZ;
560
561   //Transformed box corresponding to the selected rectangle
562   Proj (anX, anY, aZ);                  // vector orthogonal to the view plane
563   const gp_Dir aProj (anX, anY, aZ);
564
565   const gp_XY &aPf = thePolygon.First();
566   // 3D point for the 3D coordinates
567   Convert((Standard_Integer) aPf.X(), (Standard_Integer) aPf.Y(), anX, anY, aZ);
568   const gp_Pnt anEye (anX, anY, aZ);
569
570   // 3D point for the 3D coordinates
571   const gp_XY &aPl = thePolygon.Last();
572
573   Convert((Standard_Integer) aPl.X(), (Standard_Integer) aPl.Y(), anX, anY, aZ);
574
575   // Compute transformation.
576   const gp_XYZ anXdir (gp_XYZ(anX, anY, aZ) - anEye.XYZ());
577   if (anXdir.Modulus() <= gp::Resolution())
578   {
579     return;
580   }
581
582   const gp_Ax3 anAx3 (anEye, aProj, anXdir);
583   gp_Trsf aTrf;
584   aTrf.SetTransformation (anAx3);
585
586   // Prepare list of 2d points of selection polygon.
587   NCollection_List<gp_XY>           aPoints;
588   NCollection_List<gp_XY>::Iterator anIter(thePolygon);
589   Bnd_B2f                           aPolyBox;
590
591   for (; anIter.More(); anIter.Next()) {
592     const gp_XY &aP = anIter.Value();
593
594     Convert((Standard_Integer) aP.X(), (Standard_Integer) aP.Y(), anX, anY, aZ);
595     gp_XYZ aP3d(anX, anY, aZ);
596
597     aTrf.Transforms(aP3d);
598
599     gp_XY aP2d(aP3d.X(), aP3d.Y());
600
601     aPoints.Append(aP2d);
602     aPolyBox.Add(aP2d);
603   }
604
605   TColStd_PackedMapOfInteger                           mapSelected;
606   NCollection_List<NIS_InteractiveContext *>::Iterator anIterC(myContexts);
607
608   for (; anIterC.More(); anIterC.Next()) {
609     NIS_InteractiveContext * pCtx = anIterC.Value();
610     mapSelected.Clear();
611     pCtx->selectObjects (mapSelected, aPoints, aPolyBox, aTrf, isFullyIncluded);
612     pCtx->ProcessSelection (mapSelected, isForceMult);
613   }
614
615   if (theRedraw) Redraw();
616 }
617
618 //=======================================================================
619 //function : Pick
620 //purpose  :
621 //=======================================================================
622
623 Handle_NIS_InteractiveObject NIS_View::Pick (const Standard_Integer theX,
624                                              const Standard_Integer theY)
625 {
626   // Find the ray passing through the clicked point in the view window.
627   Standard_Real anX, anY, aZ, anOver;
628   Convert(theX, theY, anX, anY, aZ);  // 3D point for the 3D coordinates
629   const gp_Pnt anEye (anX, anY, aZ);
630   Proj (anX, anY, aZ);                // vector orthogonal to the view plane
631   const gp_Dir aProj (-anX, -anY, -aZ);
632   const gp_Ax1 anAxis (anEye, aProj);
633
634   Convert (theX+1, theY+1, anX, anY, aZ);
635   anOver = ((gp_XYZ(anX, anY, aZ) - anEye.XYZ()) ^ aProj.XYZ()).Modulus() * 1.5;
636
637   return Pick(anAxis, anOver, Standard_True);
638 }
639
640 //=======================================================================
641 //function : Pick
642 //purpose  :
643 //=======================================================================
644
645 Handle_NIS_InteractiveObject NIS_View::Pick
646                                 (const gp_Ax1&          theAxis,
647                                  const Standard_Real    theOver,
648                                  const Standard_Boolean isOnlySelectable)
649 {
650   typedef NCollection_List<NIS_InteractiveContext::DetectedEnt> LstDetected;
651   Standard_Real                 aDistance (0.1 * RealLast());
652   Handle(NIS_InteractiveObject) aSelected, aTmpSel;
653   LstDetected aDetected;
654
655   NCollection_List<NIS_InteractiveContext *>::Iterator anIterC (myContexts);
656   for (; anIterC.More(); anIterC.Next()) {
657     const Standard_Real aDist =
658       anIterC.Value()->selectObject (aTmpSel, aDetected, theAxis, theOver,
659                                      isOnlySelectable);
660     if (aDist < aDistance) {
661       aDistance = aDist;
662       aSelected = aTmpSel;
663     }
664   }
665
666   // simple iterating is enough to create list of detected objects
667   // in the order of increasing distance
668   myDetected.Clear();
669   for (LstDetected::Iterator anIt(aDetected); anIt.More(); anIt.Next())
670     myDetected.Append(anIt.Value().PObj);
671
672   return aSelected;
673 }
674