Commit | Line | Data |
---|---|---|
b311480e | 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 | ||
7fd59977 | 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> | |
ffe2bea7 A |
26 | #include <Bnd_B2f.hxx> |
27 | #include <TColStd_MapIteratorOfPackedMapOfInteger.hxx> | |
cfd5fa01 | 28 | |
29 | #include <OpenGl_GlCore11.hxx> | |
7fd59977 | 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) | |
cfd5fa01 | 41 | : V3d_OrthographicView (theViewer), |
ffe2bea7 A |
42 | myIsTopHilight(Standard_False), |
43 | myDoHilightSelected(Standard_True) | |
7fd59977 | 44 | { |
ffe2bea7 A |
45 | if (!theWindow.IsNull()) |
46 | V3d_View::SetWindow (theWindow, NULL, &MyCallback, this); | |
7fd59977 | 47 | } |
48 | ||
49 | //======================================================================= | |
50 | //function : SetWindow | |
cfd5fa01 | 51 | //purpose : |
7fd59977 | 52 | //======================================================================= |
53 | ||
54 | void NIS_View::SetWindow(const Handle(Aspect_Window) &theWindow) | |
55 | { | |
ffe2bea7 | 56 | V3d_View::SetWindow (theWindow, NULL, &MyCallback, this); |
7fd59977 | 57 | } |
58 | ||
59 | // //======================================================================= | |
60 | // //function : ~NIS_View | |
61 | // //purpose : Destructor | |
62 | // //======================================================================= | |
63 | ||
64 | // NIS_View::~NIS_View() | |
65 | // {} | |
66 | ||
67 | ||
68 | //======================================================================= | |
69 | //function : AddContext | |
cfd5fa01 | 70 | //purpose : |
7fd59977 | 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 | |
cfd5fa01 | 86 | //purpose : |
7fd59977 | 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 | } | |
ffe2bea7 A |
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 | } | |
7fd59977 | 105 | } |
106 | ||
107 | //======================================================================= | |
108 | //function : FitAll3d | |
cfd5fa01 | 109 | //purpose : |
7fd59977 | 110 | //======================================================================= |
111 | ||
ffe2bea7 A |
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 | |
1d47d8d0 | 132 | Standard_Real Umin = 0.,Umax = 0.,Vmin = 0.,Vmax = 0.,U,V,W; |
ffe2bea7 A |
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 | |
cfd5fa01 | 195 | //purpose : |
ffe2bea7 A |
196 | //======================================================================= |
197 | ||
198 | Bnd_B3f NIS_View::GetBndBox() const | |
7fd59977 | 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 | ||
7fd59977 | 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 | ||
ffe2bea7 A |
222 | return aBox; |
223 | } | |
224 | ||
225 | //======================================================================= | |
226 | //function : GetBndBox | |
cfd5fa01 | 227 | //purpose : |
ffe2bea7 A |
228 | //======================================================================= |
229 | ||
cfd5fa01 | 230 | void NIS_View::GetBndBox( Standard_Integer& theXMin, Standard_Integer& theXMax, |
ffe2bea7 A |
231 | Standard_Integer& theYMin, Standard_Integer& theYMax ) const |
232 | { | |
cfd5fa01 | 233 | theXMin = theYMin = 0; |
ffe2bea7 A |
234 | theXMax = theYMax = -1; |
235 | ||
236 | Bnd_B3f aBox = GetBndBox(); | |
237 | ||
7fd59977 | 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 | |
cfd5fa01 | 261 | // WindowFit (aLimp[0], aLimp[2], aLimp[1], aLimp[3]); |
ffe2bea7 A |
262 | theXMin = aLimp[0]; |
263 | theXMax = aLimp[1]; | |
264 | theYMin = aLimp[2]; | |
265 | theYMax = aLimp[3]; | |
cfd5fa01 | 266 | } |
7fd59977 | 267 | } |
268 | } | |
269 | ||
270 | ||
271 | //======================================================================= | |
272 | //function : MyCallback | |
cfd5fa01 | 273 | //purpose : |
7fd59977 | 274 | //======================================================================= |
275 | ||
276 | int NIS_View::MyCallback (Aspect_Drawable /* Window ID */, | |
cfd5fa01 | 277 | void* ptrData, |
b299a91c | 278 | Aspect_GraphicCallbackStruct* callData /* call data */) |
7fd59977 | 279 | { |
b299a91c A |
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; | |
cfd5fa01 | 287 | |
7fd59977 | 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 | ||
7fd59977 | 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 | ||
ffe2bea7 A |
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 | ||
7fd59977 | 359 | for (anIter = thisView->myContexts; anIter.More(); anIter.Next()) |
360 | anIter.Value()->redraw (thisView, NIS_Drawer::Draw_Normal); | |
ffe2bea7 A |
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 | ||
7fd59977 | 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); | |
ffe2bea7 A |
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); | |
7fd59977 | 382 | |
383 | return 0; | |
384 | } | |
385 | ||
386 | //======================================================================= | |
387 | //function : DynamicHilight | |
cfd5fa01 | 388 | //purpose : |
7fd59977 | 389 | //======================================================================= |
390 | ||
391 | void NIS_View::DynamicHilight (const Standard_Integer theX, | |
392 | const Standard_Integer theY) | |
393 | { | |
ffe2bea7 | 394 | myDetected.Clear(); |
7fd59977 | 395 | const Handle(NIS_InteractiveObject) aSelected = Pick (theX, theY); |
396 | ||
cfd5fa01 | 397 | // ASV: if at least one Context returns IsSelectable()==False, |
7fd59977 | 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) | |
ffe2bea7 A |
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() || | |
cfd5fa01 | 412 | (myDoHilightSelected == Standard_False && |
ffe2bea7 A |
413 | aSelected->GetDrawer()->GetContext()->IsSelected(aSelected))) |
414 | { | |
7fd59977 | 415 | myDynHilighted.Nullify(); |
ffe2bea7 | 416 | } |
7fd59977 | 417 | else { |
418 | aSelected->GetDrawer()->SetDynamicHilighted (Standard_True, | |
419 | aSelected, aView); | |
420 | myDynHilighted = aSelected; | |
421 | } | |
422 | Redraw(); | |
423 | } | |
424 | } | |
425 | ||
426 | //======================================================================= | |
427 | //function : DynamicUnhilight | |
cfd5fa01 | 428 | //purpose : |
7fd59977 | 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); | |
ffe2bea7 A |
435 | if (myDynHilighted->GetDrawer().IsNull() == Standard_False) |
436 | myDynHilighted->GetDrawer()->SetDynamicHilighted (Standard_False, | |
437 | myDynHilighted, aView); | |
7fd59977 | 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, | |
ffe2bea7 A |
450 | const Standard_Boolean isForceMultiple, |
451 | const Standard_Boolean theRedraw) | |
7fd59977 | 452 | { |
ffe2bea7 | 453 | myDetected.Clear(); |
7fd59977 | 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 | } | |
ffe2bea7 | 464 | if (theRedraw) Redraw(); |
7fd59977 | 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, | |
ffe2bea7 A |
477 | const Standard_Boolean isFullyIncluded, |
478 | const Standard_Boolean theRedraw) | |
7fd59977 | 479 | { |
ffe2bea7 | 480 | myDetected.Clear(); |
7fd59977 | 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 | } | |
ffe2bea7 | 516 | if (theRedraw) Redraw(); |
7fd59977 | 517 | } |
518 | ||
ffe2bea7 A |
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()); | |
476ed21f | 551 | if (anXdir.Modulus() <= gp::Resolution()) |
552 | { | |
553 | return; | |
554 | } | |
555 | ||
ffe2bea7 A |
556 | const gp_Ax3 anAx3 (anEye, aProj, anXdir); |
557 | gp_Trsf aTrf; | |
558 | aTrf.SetTransformation (anAx3); | |
ffe2bea7 A |
559 | |
560 | // Prepare list of 2d points of selection polygon. | |
561 | NCollection_List<gp_XY> aPoints; | |
562 | NCollection_List<gp_XY>::Iterator anIter(thePolygon); | |
563 | Bnd_B2f aPolyBox; | |
564 | ||
565 | for (; anIter.More(); anIter.Next()) { | |
566 | const gp_XY &aP = anIter.Value(); | |
567 | ||
568 | Convert((Standard_Integer) aP.X(), (Standard_Integer) aP.Y(), anX, anY, aZ); | |
569 | gp_XYZ aP3d(anX, anY, aZ); | |
570 | ||
571 | aTrf.Transforms(aP3d); | |
572 | ||
573 | gp_XY aP2d(aP3d.X(), aP3d.Y()); | |
574 | ||
575 | aPoints.Append(aP2d); | |
576 | aPolyBox.Add(aP2d); | |
577 | } | |
578 | ||
579 | TColStd_PackedMapOfInteger mapSelected; | |
580 | NCollection_List<NIS_InteractiveContext *>::Iterator anIterC(myContexts); | |
581 | ||
582 | for (; anIterC.More(); anIterC.Next()) { | |
583 | NIS_InteractiveContext * pCtx = anIterC.Value(); | |
584 | mapSelected.Clear(); | |
585 | pCtx->selectObjects (mapSelected, aPoints, aPolyBox, aTrf, isFullyIncluded); | |
586 | pCtx->ProcessSelection (mapSelected, isForceMult); | |
587 | } | |
588 | ||
589 | if (theRedraw) Redraw(); | |
590 | } | |
7fd59977 | 591 | |
592 | //======================================================================= | |
593 | //function : Pick | |
cfd5fa01 | 594 | //purpose : |
7fd59977 | 595 | //======================================================================= |
596 | ||
ffe2bea7 A |
597 | Handle_NIS_InteractiveObject NIS_View::Pick (const Standard_Integer theX, |
598 | const Standard_Integer theY) | |
7fd59977 | 599 | { |
600 | // Find the ray passing through the clicked point in the view window. | |
601 | Standard_Real anX, anY, aZ, anOver; | |
602 | Convert(theX, theY, anX, anY, aZ); // 3D point for the 3D coordinates | |
603 | const gp_Pnt anEye (anX, anY, aZ); | |
604 | Proj (anX, anY, aZ); // vector orthogonal to the view plane | |
605 | const gp_Dir aProj (-anX, -anY, -aZ); | |
606 | const gp_Ax1 anAxis (anEye, aProj); | |
607 | ||
608 | Convert (theX+1, theY+1, anX, anY, aZ); | |
609 | anOver = ((gp_XYZ(anX, anY, aZ) - anEye.XYZ()) ^ aProj.XYZ()).Modulus() * 1.5; | |
610 | ||
611 | return Pick(anAxis, anOver, Standard_True); | |
612 | } | |
613 | ||
614 | //======================================================================= | |
615 | //function : Pick | |
cfd5fa01 | 616 | //purpose : |
7fd59977 | 617 | //======================================================================= |
618 | ||
619 | Handle_NIS_InteractiveObject NIS_View::Pick | |
620 | (const gp_Ax1& theAxis, | |
621 | const Standard_Real theOver, | |
ffe2bea7 | 622 | const Standard_Boolean isOnlySelectable) |
7fd59977 | 623 | { |
ffe2bea7 | 624 | typedef NCollection_List<NIS_InteractiveContext::DetectedEnt> LstDetected; |
7fd59977 | 625 | Standard_Real aDistance (0.1 * RealLast()); |
626 | Handle(NIS_InteractiveObject) aSelected, aTmpSel; | |
ffe2bea7 | 627 | LstDetected aDetected; |
7fd59977 | 628 | |
629 | NCollection_List<NIS_InteractiveContext *>::Iterator anIterC (myContexts); | |
630 | for (; anIterC.More(); anIterC.Next()) { | |
631 | const Standard_Real aDist = | |
ffe2bea7 | 632 | anIterC.Value()->selectObject (aTmpSel, aDetected, theAxis, theOver, |
7fd59977 | 633 | isOnlySelectable); |
634 | if (aDist < aDistance) { | |
635 | aDistance = aDist; | |
636 | aSelected = aTmpSel; | |
637 | } | |
638 | } | |
ffe2bea7 A |
639 | |
640 | // simple iterating is enough to create list of detected objects | |
641 | // in the order of increasing distance | |
642 | myDetected.Clear(); | |
643 | for (LstDetected::Iterator anIt(aDetected); anIt.More(); anIt.Next()) | |
644 | myDetected.Append(anIt.Value().PObj); | |
645 | ||
7fd59977 | 646 | return aSelected; |
647 | } | |
ffe2bea7 | 648 |