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