913a4c4a |
1 | // Created on: 2011-10-20 |
2 | // Created by: Roman KOZLOV |
3 | // Copyright (c) 2011-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 <IVtkOCC_ViewerSelector.hxx> |
17 | #include <Select3D_SensitiveBox.hxx> |
18 | #include <TColgp_Array1OfPnt2d.hxx> |
19 | #include <gp_Quaternion.hxx> |
20 | #include <Graphic3d_Camera.hxx> |
21 | |
22 | IMPLEMENT_STANDARD_HANDLE( IVtkOCC_ViewerSelector, SelectMgr_ViewerSelector ) |
23 | IMPLEMENT_STANDARD_RTTIEXT( IVtkOCC_ViewerSelector, SelectMgr_ViewerSelector ) |
24 | |
25 | //============================================================================ |
26 | // Method: Constructor |
27 | // Purpose: |
28 | //============================================================================ |
29 | IVtkOCC_ViewerSelector::IVtkOCC_ViewerSelector() |
30 | : SelectMgr_ViewerSelector(), |
31 | myPixTol(2), |
32 | myToUpdateTol(Standard_True) |
33 | { |
34 | for (Standard_Integer i=0;i<=13;i++) {myCoeff [i] = 0.;myPrevCoeff[i]=0.0;} |
35 | for (Standard_Integer j=0;j<2;j++) {myCenter [j] = 0.;myPrevCenter[j]=0.0;} |
36 | } |
37 | |
38 | //============================================================================ |
39 | // Method: Convert |
40 | // Purpose: Projects all sensitive entities from the given selection container |
41 | // to 2D space |
42 | //============================================================================ |
43 | void IVtkOCC_ViewerSelector::Convert (const Handle(SelectMgr_Selection)& theSelection) |
44 | { |
45 | for (theSelection->Init(); theSelection->More(); theSelection->Next()) |
46 | { |
47 | if(theSelection->Sensitive()->NeedsConversion()) |
48 | { |
49 | Handle(Select3D_SensitiveEntity) aSensEntity = |
50 | *((Handle(Select3D_SensitiveEntity)*) &(theSelection->Sensitive())); |
51 | aSensEntity->Project (myPrj); |
52 | if (!tosort) |
53 | { |
54 | tosort = Standard_True; |
55 | } |
56 | } |
57 | } |
58 | } |
59 | |
60 | //============================================================================ |
61 | // Method: Pick |
62 | // Purpose: Implements point picking |
63 | //============================================================================ |
64 | void IVtkOCC_ViewerSelector::Pick (const Standard_Integer theXPix, |
65 | const Standard_Integer theYPix, |
66 | const IVtk_IView::Handle& theView) |
67 | { |
68 | myclip.SetVoid(); |
69 | Update (theView); |
70 | gp_XY aDispPnt (theXPix, theYPix); |
71 | gp_XYZ aWorldPnt; |
72 | gp_Pnt2d aP2d; |
73 | theView->DisplayToWorld (aDispPnt, aWorldPnt); |
74 | myPrj->Project (gp_Pnt (aWorldPnt), aP2d); |
75 | InitSelect (aP2d.X(), aP2d.Y()); |
76 | } |
77 | |
78 | //============================================================================ |
79 | // Method: Pick |
80 | // Purpose: Picking by rectangle |
81 | //============================================================================ |
82 | void IVtkOCC_ViewerSelector::Pick (const Standard_Integer theXMin, |
83 | const Standard_Integer theYMin, |
84 | const Standard_Integer theXMax, |
85 | const Standard_Integer theYMax, |
86 | const IVtk_IView::Handle& theView) |
87 | { |
88 | if (myToUpdateTol) |
89 | { |
90 | // Compute and set a sensitivity tolerance according to the renderer (viewport). |
91 | // TODO: Think if this works well in perspective view...'cause result depends |
92 | // on position on the screen, but we always use the point close to the |
93 | // screen's origin... |
94 | gp_XYZ aWorldPnt1, aWorldPnt2; |
95 | gp_XY aDispPnt1 (0.0, 0.0); |
96 | gp_XY aDispPnt2 (myPixTol, 0.0); |
97 | theView->DisplayToWorld (aDispPnt1, aWorldPnt1); |
98 | theView->DisplayToWorld (aDispPnt2, aWorldPnt2); |
99 | gp_Pnt aPnt1 (aWorldPnt1); |
100 | gp_Pnt aPnt2 (aWorldPnt2); |
101 | SetSensitivity (aPnt2.Distance (aPnt1)); |
102 | myToUpdateTol = Standard_False; |
103 | } |
104 | Update (theView); |
105 | |
106 | gp_XY aDispPnt1 (theXMin, theYMin); |
107 | gp_XY aDispPnt2 (theXMax, theYMax); |
108 | gp_XYZ aWorldPnt1, aWorldPnt2; |
109 | |
110 | gp_Pnt2d aP2d_1, aP2d_2; |
111 | theView->DisplayToWorld (aDispPnt1, aWorldPnt1); |
112 | theView->DisplayToWorld (aDispPnt2, aWorldPnt2); |
113 | |
114 | myPrj->Project (gp_Pnt (aWorldPnt1), aP2d_1); |
115 | myPrj->Project (gp_Pnt (aWorldPnt2), aP2d_2); |
116 | |
117 | InitSelect (Min (aP2d_1.X(), aP2d_2.X()), |
118 | Min (aP2d_1.Y(), aP2d_2.Y()), |
119 | Max (aP2d_1.X(), aP2d_2.X()), |
120 | Max (aP2d_1.Y(), aP2d_2.Y())); |
121 | } |
122 | |
123 | //============================================================================ |
124 | // Method: Pick |
125 | // Purpose: |
126 | //============================================================================ |
127 | void IVtkOCC_ViewerSelector::Pick (double** thePoly, |
128 | const int theNbPoints, |
129 | const IVtk_IView::Handle& theView) |
130 | { |
131 | TColgp_Array1OfPnt2d aPolyline (1, theNbPoints); |
132 | |
133 | if (myToUpdateTol) |
134 | { |
135 | // Compute and set a sensitivity tolerance according to the renderer (viewport). |
136 | // TODO: Think if this works well in perspective view...'cause result depends |
137 | // on position on the screen, but we always use the point close to the |
138 | // screen's origin... |
139 | gp_XYZ aWorldPnt1, aWorldPnt2; |
140 | gp_XY aDispPnt1 (0.0, 0.0); |
141 | gp_XY aDispPnt2 (myPixTol, 0.0); |
142 | theView->DisplayToWorld (aDispPnt1, aWorldPnt1); |
143 | theView->DisplayToWorld (aDispPnt2, aWorldPnt2); |
144 | gp_Pnt aPnt1 (aWorldPnt1); |
145 | gp_Pnt aPnt2 (aWorldPnt2); |
146 | SetSensitivity (aPnt2.Distance (aPnt1)); |
147 | myToUpdateTol = Standard_False; |
148 | } |
149 | |
150 | Update (theView); |
151 | |
152 | // Build TColgp_Array1OfPnt2d from input array of doubles |
153 | gp_XYZ aWorldPnt; |
154 | |
155 | for (Standard_Integer anIt = 0; anIt < theNbPoints; anIt++) |
156 | { |
157 | gp_XY aDispPnt = thePoly[anIt][2] != 0 ? gp_XY (thePoly[anIt][0] / thePoly[anIt][2], thePoly[anIt][1] / thePoly[anIt][2]) |
158 | : gp_XY (thePoly[anIt][0], thePoly[anIt][1]); |
159 | gp_Pnt2d aP2d; |
160 | theView->DisplayToWorld (aDispPnt, aWorldPnt); |
161 | myPrj->Project (gp_Pnt (aWorldPnt), aP2d); |
162 | aPolyline.SetValue (anIt + 1, aP2d); |
163 | } |
164 | |
165 | InitSelect (aPolyline); |
166 | } |
167 | |
168 | //============================================================================ |
169 | // Method: Update |
170 | // Purpose: Checks if some projection parameters have changed, |
171 | // and updates the 2D projections of all sensitive entities if necessary. |
172 | //============================================================================ |
173 | Standard_Boolean IVtkOCC_ViewerSelector::Update (const IVtk_IView::Handle& theView) |
174 | { |
175 | static Standard_Real aZoom (0.0); |
176 | |
177 | // No focal distance by default |
178 | myPrevCoeff[9] = 0.0; |
179 | // Parallel projection by default |
180 | myPrevCoeff[10] = 0.0; |
181 | |
182 | // Flag related to perspective or parallel projection |
183 | Standard_Boolean isPerspective = theView->IsPerspective(); |
184 | |
185 | // For perspective projections only |
186 | if (isPerspective) |
187 | { |
188 | // Flag = 1 if perspective projection |
189 | myPrevCoeff[10] = 1.0; |
190 | // Focal distance |
191 | myPrevCoeff[9] = theView->GetDistance(); |
192 | } |
193 | // View point |
194 | // Use (0,0,0) as a view reference point: |
195 | |
196 | theView->GetPosition (myPrevCoeff[0], myPrevCoeff[1], myPrevCoeff[2]); |
197 | |
198 | // Orientation |
199 | theView->GetViewUp (myPrevCoeff[3], myPrevCoeff[4], myPrevCoeff[5]); |
200 | // Projection direction vector |
201 | theView->GetDirectionOfProjection (myPrevCoeff[6], myPrevCoeff[7], myPrevCoeff[8]); |
202 | |
203 | // 3D Scale |
204 | theView->GetScale (myPrevCoeff[11], myPrevCoeff[12], myPrevCoeff[13]); |
205 | |
206 | // Return the center of this viewport in display coordinates. |
207 | theView->GetViewCenter (myPrevCenter[0], myPrevCenter[1]); |
208 | |
209 | Standard_Integer anIt; |
210 | |
211 | for (anIt=0; anIt <= 13 && (myPrevCoeff[anIt] == myCoeff[anIt]); anIt++) { } |
212 | |
213 | if (anIt <= 13 || (myPrevCenter[0] != myCenter[0]) || (myPrevCenter[1] != myCenter[1])) |
214 | { |
215 | toupdate = Standard_True; |
216 | myToUpdateTol = Standard_True; |
217 | |
218 | for (Standard_Integer anI = anIt; anI <= 13; anI++) |
219 | { |
220 | myCoeff[anI] = myPrevCoeff[anI]; |
221 | } |
222 | |
223 | for (Standard_Integer aJ = 0; aJ < 2; aJ++) |
224 | { |
225 | myCenter[aJ] = myPrevCenter[aJ]; |
226 | } |
227 | |
228 | // For orthographic view use only direction of projection and up vector |
229 | // Panning, and zooming has no effect on 2D selection sensitives. |
230 | Handle (Graphic3d_Camera) aCamera = new Graphic3d_Camera(); |
231 | |
232 | aCamera->SetProjectionType (Graphic3d_Camera::Projection_Orthographic); |
233 | aCamera->SetCenter (gp::Origin()); |
234 | aCamera->SetDirection (gp_Dir (-myCoeff[6], -myCoeff[7], -myCoeff[8])); |
235 | aCamera->SetUp (gp_Dir (myCoeff[3], myCoeff[4], myCoeff[5])); |
236 | aCamera->SetDistance (1.0); |
237 | aCamera->SetAxialScale (gp_XYZ (myCoeff[11], myCoeff[12], myCoeff[13])); |
238 | |
239 | myPrj = new Select3D_Projector (aCamera->OrientationMatrix(), Graphic3d_Mat4d()); |
240 | } |
241 | |
242 | if (isPerspective) |
243 | { |
244 | if (Abs(theView->GetViewAngle() - aZoom) > 1.e-3) |
245 | { |
246 | myToUpdateTol = Standard_True; |
247 | aZoom = theView->GetViewAngle(); |
248 | } |
249 | } |
250 | else |
251 | { |
252 | if (Abs (theView->GetParallelScale() - aZoom) > 1.e-3) |
253 | { |
254 | myToUpdateTol = Standard_True; |
255 | aZoom = theView->GetParallelScale(); |
256 | } |
257 | } |
258 | |
259 | if(myToUpdateTol) |
260 | { |
261 | // Compute and set a sensitivity tolerance according to the view |
262 | gp_XYZ aWorldPnt1, aWorldPnt2; |
263 | gp_XY aDispPnt1 (0.0, 0.0); |
264 | gp_XY aDispPnt2 (myPixTol, 0.0); |
265 | |
266 | theView->DisplayToWorld (aDispPnt1, aWorldPnt1); |
267 | theView->DisplayToWorld (aDispPnt2, aWorldPnt2); |
268 | gp_Pnt aPnt1 (aWorldPnt1); |
269 | gp_Pnt aPnt2 (aWorldPnt2); |
270 | SetSensitivity (aPnt2.Distance (aPnt1)); |
271 | |
272 | myToUpdateTol = Standard_False; |
273 | } |
274 | |
275 | if(toupdate) UpdateConversion(); |
276 | if(tosort) UpdateSort(); |
277 | |
278 | return Standard_True; |
279 | } |
280 | |
281 | //============================================================================ |
282 | // Method: Activate |
283 | // Purpose: Activates the given selection |
284 | //============================================================================ |
285 | void IVtkOCC_ViewerSelector::Activate (const Handle(SelectMgr_Selection)& theSelection, |
286 | const Standard_Boolean theIsAutomaticProj) |
287 | { |
288 | tosort = Standard_True; |
289 | |
290 | if (!myselections.IsBound (theSelection)) |
291 | { |
292 | myselections.Bind (theSelection, 0); |
293 | } |
294 | else if (myselections (theSelection) != 0) |
295 | { |
296 | myselections (theSelection) = 0; |
297 | } |
298 | if (theIsAutomaticProj) |
299 | { |
300 | Convert (theSelection); |
301 | } |
302 | } |
303 | |
304 | //============================================================================ |
305 | // Method: Deactivate |
306 | // Purpose: Deactivate the given selection |
307 | //============================================================================ |
308 | void IVtkOCC_ViewerSelector::Deactivate (const Handle(SelectMgr_Selection)& theSelection) |
309 | { |
310 | if (myselections.IsBound (theSelection)) |
311 | { |
312 | myselections (theSelection) = 1; |
313 | tosort = Standard_True; |
314 | } |
315 | } |
316 | |
317 | //============================================================================ |
318 | // Method: PickingLine |
319 | // Purpose: Deactivate the given selection |
320 | //============================================================================ |
321 | gp_Lin IVtkOCC_ViewerSelector::PickingLine (const Standard_Real theX,const Standard_Real theY) const |
322 | { |
323 | return myPrj->Shoot (theX, theY); |
324 | } |