f751596e |
1 | // Created on: 2014-05-22 |
2 | // Created by: Varvara POSKONINA |
3 | // Copyright (c) 2005-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 <NCollection_Vector.hxx> |
17 | #include <Poly_Array1OfTriangle.hxx> |
18 | |
19 | #include <SelectMgr_RectangularFrustum.hxx> |
20 | |
21 | #define DOT(A, B) (A.x() * B.x() + A.y() * B.y() + A.z() * B.z()) |
22 | #define DOTp(A, B) (A.x() * B.X() + A.y() * B.Y() + A.z() * B.Z()) |
23 | #define DISTANCE(A, B) (std::sqrt ((A.x() - B.x()) * (A.x() - B.x()) + (A.y() - B.y()) * (A.y() - B.y()) + (A.z() - B.z()) * (A.z() - B.z()))) |
24 | #define DISTANCEp(A, B) (std::sqrt ((A.x() - B.X()) * (A.x() - B.X()) + (A.y() - B.Y()) * (A.y() - B.Y()) + (A.z() - B.Z()) * (A.z() - B.Z()))) |
25 | |
26 | // ======================================================================= |
27 | // function : segmentSegmentDistance |
28 | // purpose : |
29 | // ======================================================================= |
30 | void SelectMgr_RectangularFrustum::segmentSegmentDistance (const gp_Pnt& theSegPnt1, |
31 | const gp_Pnt& theSegPnt2, |
32 | Standard_Real& theDepth) |
33 | { |
34 | SelectMgr_Vec3 anU = SelectMgr_Vec3 (theSegPnt2.X() - theSegPnt1.X(), |
35 | theSegPnt2.Y() - theSegPnt1.Y(), |
36 | theSegPnt2.Z() - theSegPnt1.Z()); |
37 | SelectMgr_Vec3 aV = myViewRayDir; |
38 | SelectMgr_Vec3 aW = SelectMgr_Vec3 (theSegPnt1.X() - myNearPickedPnt.x(), |
39 | theSegPnt1.Y() - myNearPickedPnt.y(), |
40 | theSegPnt1.Z() - myNearPickedPnt.z()); |
41 | Standard_Real anA = DOT (anU, anU); |
42 | Standard_Real aB = DOT (anU, aV); |
43 | Standard_Real aC = DOT (aV, aV); |
44 | Standard_Real aD = DOT (anU, aW); |
45 | Standard_Real anE = DOT (aV, aW); |
46 | Standard_Real aCoef = anA * aC - aB * aB; |
47 | Standard_Real aSc, aSn, aSd = aCoef; |
48 | Standard_Real aTc, aTn, aTd = aCoef; |
49 | |
50 | if (aCoef < Precision::Confusion()) |
51 | { |
52 | aSn = 0.0; |
53 | aSd = 1.0; |
54 | aTn = anE; |
55 | aTd = aC; |
56 | } |
57 | else |
58 | { |
59 | aSn = (aB * anE - aC * aD); |
60 | aTn = (anA * anE - aB * aD); |
61 | if (aSn < 0.0) |
62 | { |
63 | aSn = 0.0; |
64 | aTn = anE; |
65 | aTd = aC; |
66 | } |
67 | else if (aSn > aSd) |
68 | { |
69 | aSn = aSd; |
70 | aTn = anE + aB; |
71 | aTd = aC; |
72 | } |
73 | } |
74 | |
75 | if (aTn < 0.0) |
76 | { |
77 | aTn = 0.0; |
78 | if (-aD < 0.0) |
79 | aSn = 0.0; |
80 | else if (-aD > anA) |
81 | aSn = aSd; |
82 | else { |
83 | aSn = -aD; |
84 | aSd = anA; |
85 | } |
86 | } |
87 | else if (aTn > aTd) |
88 | { |
89 | aTn = aTd; |
90 | if ((-aD + aB) < 0.0) |
91 | aSn = 0; |
92 | else if ((-aD + aB) > anA) |
93 | aSn = aSd; |
94 | else { |
95 | aSn = (-aD + aB); |
96 | aSd = anA; |
97 | } |
98 | } |
99 | aSc = (Abs (aSn) < Precision::Confusion() ? 0.0 : aSn / aSd); |
100 | aTc = (Abs (aTn) < Precision::Confusion() ? 0.0 : aTn / aTd); |
101 | |
f751596e |
102 | SelectMgr_Vec3 aClosestPnt = myNearPickedPnt + myViewRayDir * aTc; |
103 | theDepth = DISTANCE (myNearPickedPnt, aClosestPnt); |
104 | } |
105 | |
106 | // ======================================================================= |
107 | // function : segmentPlaneIntersection |
108 | // purpose : |
109 | // ======================================================================= |
110 | void SelectMgr_RectangularFrustum::segmentPlaneIntersection (const SelectMgr_Vec3& thePlane, |
111 | const gp_Pnt& thePntOnPlane, |
112 | Standard_Real& theDepth) |
113 | { |
114 | SelectMgr_Vec3 anU = myViewRayDir; |
115 | SelectMgr_Vec3 aW = SelectMgr_Vec3 (myNearPickedPnt.x() - thePntOnPlane.X(), |
116 | myNearPickedPnt.y() - thePntOnPlane.Y(), |
117 | myNearPickedPnt.z() - thePntOnPlane.Z()); |
118 | Standard_Real aD = DOT (thePlane, anU); |
119 | Standard_Real aN = -DOT (thePlane, aW); |
120 | |
121 | if (Abs (aD) < Precision::Confusion()) |
122 | { |
123 | if (Abs (aN) < Precision::Angular()) |
124 | { |
125 | theDepth = DBL_MAX; |
126 | return; |
127 | } |
128 | else |
129 | { |
130 | theDepth = DBL_MAX; |
131 | return; |
132 | } |
133 | } |
134 | |
135 | Standard_Real aParam = aN / aD; |
136 | if (aParam < 0.0 || aParam > 1.0) |
137 | { |
138 | theDepth = DBL_MAX; |
139 | return; |
140 | } |
141 | |
142 | SelectMgr_Vec3 aClosestPnt = myNearPickedPnt + anU * aParam; |
143 | theDepth = DISTANCE (myNearPickedPnt, aClosestPnt); |
144 | } |
145 | |
2157d6ac |
146 | namespace |
147 | { |
148 | // ======================================================================= |
149 | // function : computeNormals |
150 | // purpose : Computes normals to frustum faces |
151 | // ======================================================================= |
152 | void computeNormals (const SelectMgr_Vec3* theVertices, SelectMgr_Vec3* theNormals) |
153 | { |
154 | // Top |
155 | theNormals[0] = SelectMgr_Vec3::Cross (theVertices[1] - theVertices[0], |
156 | theVertices[4] - theVertices[0]); |
157 | // Bottom |
158 | theNormals[1] = SelectMgr_Vec3::Cross (theVertices[3] - theVertices[2], |
159 | theVertices[6] - theVertices[2]); |
160 | // Left |
161 | theNormals[2] = SelectMgr_Vec3::Cross (theVertices[1] - theVertices[0], |
162 | theVertices[2] - theVertices[0]); |
163 | // Right |
164 | theNormals[3] = SelectMgr_Vec3::Cross (theVertices[5] - theVertices[4], |
165 | theVertices[6] - theVertices[4]); |
166 | // Near |
167 | theNormals[4] = SelectMgr_Vec3::Cross (theVertices[6] - theVertices[4], |
168 | theVertices[0] - theVertices[4]); |
169 | // Far |
170 | theNormals[5] = SelectMgr_Vec3::Cross (theVertices[7] - theVertices[5], |
171 | theVertices[1] - theVertices[5]); |
172 | } |
173 | } |
174 | |
f751596e |
175 | // ======================================================================= |
176 | // function : Build |
177 | // purpose : Build volume according to the point and given pixel |
178 | // tolerance |
179 | // ======================================================================= |
180 | void SelectMgr_RectangularFrustum::Build (const gp_Pnt2d &thePoint) |
181 | { |
182 | myNearPickedPnt = myBuilder->ProjectPntOnViewPlane (thePoint.X(), thePoint.Y(), 0.0); |
183 | myFarPickedPnt = myBuilder->ProjectPntOnViewPlane (thePoint.X(), thePoint.Y(), 1.0); |
184 | myViewRayDir = myFarPickedPnt - myNearPickedPnt; |
28ee613b |
185 | myMousePos = thePoint; |
f751596e |
186 | |
187 | // LeftTopNear |
188 | myVertices[0] = myBuilder->ProjectPntOnViewPlane (thePoint.X() - myPixelTolerance / 2.0, |
189 | thePoint.Y() + myPixelTolerance / 2.0, |
190 | 0.0); |
191 | // LeftTopFar |
192 | myVertices[1] = myBuilder->ProjectPntOnViewPlane (thePoint.X() - myPixelTolerance / 2.0, |
193 | thePoint.Y() + myPixelTolerance / 2.0, |
194 | 1.0); |
195 | // LeftBottomNear |
196 | myVertices[2] = myBuilder->ProjectPntOnViewPlane (thePoint.X() - myPixelTolerance / 2.0, |
197 | thePoint.Y() - myPixelTolerance / 2.0, |
198 | 0.0); |
199 | // LeftBottomFar |
200 | myVertices[3] = myBuilder->ProjectPntOnViewPlane (thePoint.X() - myPixelTolerance / 2.0, |
201 | thePoint.Y() - myPixelTolerance / 2.0, |
202 | 1.0); |
203 | // RightTopNear |
204 | myVertices[4] = myBuilder->ProjectPntOnViewPlane (thePoint.X() + myPixelTolerance / 2.0, |
205 | thePoint.Y() + myPixelTolerance / 2.0, |
206 | 0.0); |
207 | // RightTopFar |
208 | myVertices[5] = myBuilder->ProjectPntOnViewPlane (thePoint.X() + myPixelTolerance / 2.0, |
209 | thePoint.Y() + myPixelTolerance / 2.0, |
210 | 1.0); |
211 | // RightBottomNear |
212 | myVertices[6] = myBuilder->ProjectPntOnViewPlane (thePoint.X() + myPixelTolerance / 2.0, |
213 | thePoint.Y() - myPixelTolerance / 2.0, |
214 | 0.0); |
215 | // RightBottomFar |
216 | myVertices[7] = myBuilder->ProjectPntOnViewPlane (thePoint.X() + myPixelTolerance / 2.0, |
217 | thePoint.Y() - myPixelTolerance / 2.0, |
218 | 1.0); |
2157d6ac |
219 | |
220 | // compute frustum normals |
221 | computeNormals (myVertices, myPlanes); |
f751596e |
222 | |
223 | for (Standard_Integer aPlaneIdx = 0; aPlaneIdx < 6; ++aPlaneIdx) |
224 | { |
225 | Standard_Real aMax = -DBL_MAX; |
226 | Standard_Real aMin = DBL_MAX; |
227 | const SelectMgr_Vec3 aPlane = myPlanes[aPlaneIdx]; |
228 | for (Standard_Integer aVertIdx = 0; aVertIdx < 8; ++aVertIdx) |
229 | { |
230 | Standard_Real aProjection = DOT (aPlane, myVertices[aVertIdx]); |
231 | aMax = Max (aMax, aProjection); |
232 | aMin = Min (aMin, aProjection); |
233 | } |
234 | myMaxVertsProjections[aPlaneIdx] = aMax; |
235 | myMinVertsProjections[aPlaneIdx] = aMin; |
236 | } |
237 | |
238 | SelectMgr_Vec3 aDimensions[3] = |
239 | { |
240 | SelectMgr_Vec3 (1.0, 0.0, 0.0), |
241 | SelectMgr_Vec3 (0.0, 1.0, 0.0), |
242 | SelectMgr_Vec3 (0.0, 0.0, 1.0) |
243 | }; |
244 | |
245 | for (Standard_Integer aDim = 0; aDim < 3; ++aDim) |
246 | { |
247 | Standard_Real aMax = -DBL_MAX; |
248 | Standard_Real aMin = DBL_MAX; |
249 | for (Standard_Integer aVertIdx = 0; aVertIdx < 8; ++aVertIdx) |
250 | { |
251 | Standard_Real aProjection = DOT (aDimensions[aDim], myVertices[aVertIdx]); |
252 | aMax = Max (aProjection, aMax); |
253 | aMin = Min (aProjection, aMin); |
254 | } |
255 | myMaxOrthoVertsProjections[aDim] = aMax; |
256 | myMinOrthoVertsProjections[aDim] = aMin; |
257 | } |
258 | |
259 | // Horizontal |
260 | myEdgeDirs[0] = myVertices[4] - myVertices[0]; |
261 | // Vertical |
262 | myEdgeDirs[1] = myVertices[2] - myVertices[0]; |
263 | // LeftLower |
264 | myEdgeDirs[2] = myVertices[2] - myVertices[3]; |
265 | // RightLower |
266 | myEdgeDirs[3] = myVertices[6] - myVertices[7]; |
267 | // LeftUpper |
268 | myEdgeDirs[4] = myVertices[0] - myVertices[1]; |
269 | // RightUpper |
270 | myEdgeDirs[5] = myVertices[4] - myVertices[5]; |
271 | } |
272 | |
273 | // ======================================================================= |
274 | // function : Build |
275 | // purpose : Build volume according to the selected rectangle |
276 | // ======================================================================= |
277 | void SelectMgr_RectangularFrustum::Build (const gp_Pnt2d& theMinPnt, |
278 | const gp_Pnt2d& theMaxPnt) |
279 | { |
280 | myNearPickedPnt = myBuilder->ProjectPntOnViewPlane ((theMinPnt.X() + theMaxPnt.X()) * 0.5, |
281 | (theMinPnt.Y() + theMaxPnt.Y()) * 0.5, |
282 | 0.0); |
283 | myFarPickedPnt = myBuilder->ProjectPntOnViewPlane ((theMinPnt.X() + theMaxPnt.X()) * 0.5, |
284 | (theMinPnt.Y() + theMaxPnt.Y()) * 0.5, |
285 | 1.0); |
286 | myViewRayDir = myFarPickedPnt - myNearPickedPnt; |
287 | |
288 | // LeftTopNear |
289 | myVertices[0] = myBuilder->ProjectPntOnViewPlane (theMinPnt.X(), |
290 | theMaxPnt.Y(), |
291 | 0.0); |
292 | // LeftTopFar |
293 | myVertices[1] = myBuilder->ProjectPntOnViewPlane (theMinPnt.X(), |
294 | theMaxPnt.Y(), |
295 | 1.0); |
296 | // LeftBottomNear |
297 | myVertices[2] = myBuilder->ProjectPntOnViewPlane (theMinPnt.X(), |
298 | theMinPnt.Y(), |
299 | 0.0); |
300 | // LeftBottomFar |
301 | myVertices[3] = myBuilder->ProjectPntOnViewPlane (theMinPnt.X(), |
302 | theMinPnt.Y(), |
303 | 1.0); |
304 | // RightTopNear |
305 | myVertices[4] = myBuilder->ProjectPntOnViewPlane (theMaxPnt.X(), |
306 | theMaxPnt.Y(), |
307 | 0.0); |
308 | // RightTopFar |
309 | myVertices[5] = myBuilder->ProjectPntOnViewPlane (theMaxPnt.X(), |
310 | theMaxPnt.Y(), |
311 | 1.0); |
312 | // RightBottomNear |
313 | myVertices[6] = myBuilder->ProjectPntOnViewPlane (theMaxPnt.X(), |
314 | theMinPnt.Y(), |
315 | 0.0); |
316 | // RightBottomFar |
2157d6ac |
317 | myVertices[7] = myBuilder->ProjectPntOnViewPlane (theMaxPnt.X(), |
f751596e |
318 | theMinPnt.Y(), |
319 | 1.0); |
320 | |
2157d6ac |
321 | // compute frustum normals |
322 | computeNormals (myVertices, myPlanes); |
f751596e |
323 | |
324 | for (Standard_Integer aPlaneIdx = 0; aPlaneIdx < 6; ++aPlaneIdx) |
325 | { |
326 | Standard_Real aMax = -DBL_MAX; |
327 | Standard_Real aMin = DBL_MAX; |
328 | const SelectMgr_Vec3 aPlane = myPlanes[aPlaneIdx]; |
329 | for (Standard_Integer aVertIdx = 0; aVertIdx < 8; ++aVertIdx) |
330 | { |
331 | Standard_Real aProjection = DOT (aPlane, myVertices[aVertIdx]); |
332 | aMax = Max (aMax, aProjection); |
333 | aMin = Min (aMin, aProjection); |
334 | } |
335 | myMaxVertsProjections[aPlaneIdx] = aMax; |
336 | myMinVertsProjections[aPlaneIdx] = aMin; |
337 | } |
338 | |
339 | SelectMgr_Vec3 aDimensions[3] = |
340 | { |
341 | SelectMgr_Vec3 (1.0, 0.0, 0.0), |
342 | SelectMgr_Vec3 (0.0, 1.0, 0.0), |
343 | SelectMgr_Vec3 (0.0, 0.0, 1.0) |
344 | }; |
345 | |
346 | for (Standard_Integer aDim = 0; aDim < 3; ++aDim) |
347 | { |
348 | Standard_Real aMax = -DBL_MAX; |
349 | Standard_Real aMin = DBL_MAX; |
350 | for (Standard_Integer aVertIdx = 0; aVertIdx < 8; ++aVertIdx) |
351 | { |
352 | Standard_Real aProjection = DOT (aDimensions[aDim], myVertices[aVertIdx]); |
353 | aMax = Max (aMax, aProjection); |
354 | aMin = Min (aMin, aProjection); |
355 | } |
356 | myMaxOrthoVertsProjections[aDim] = aMax; |
357 | myMinOrthoVertsProjections[aDim] = aMin; |
358 | } |
359 | |
360 | // Horizontal |
361 | myEdgeDirs[0] = myVertices[4] - myVertices[0]; |
362 | // Vertical |
363 | myEdgeDirs[1] = myVertices[2] - myVertices[0]; |
364 | // LeftLower |
365 | myEdgeDirs[2] = myVertices[2] - myVertices[3]; |
366 | // RightLower |
367 | myEdgeDirs[3] = myVertices[6] - myVertices[7]; |
368 | // LeftUpper |
369 | myEdgeDirs[4] = myVertices[0] - myVertices[1]; |
370 | // RightUpper |
371 | myEdgeDirs[5] = myVertices[4] - myVertices[5]; |
372 | } |
373 | |
374 | // ======================================================================= |
375 | // function : Transform |
376 | // purpose : Returns a copy of the frustum transformed according to the matrix given |
377 | // ======================================================================= |
378 | NCollection_Handle<SelectMgr_BaseFrustum> SelectMgr_RectangularFrustum::Transform (const gp_Trsf& theTrsf) |
379 | { |
380 | SelectMgr_RectangularFrustum* aRes = new SelectMgr_RectangularFrustum(); |
381 | |
382 | aRes->myNearPickedPnt = SelectMgr_MatOp::Transform (theTrsf, myNearPickedPnt); |
383 | aRes->myFarPickedPnt = SelectMgr_MatOp::Transform (theTrsf, myFarPickedPnt); |
384 | aRes->myViewRayDir = aRes->myFarPickedPnt - aRes->myNearPickedPnt; |
385 | |
386 | aRes->myIsOrthographic = myIsOrthographic; |
387 | |
388 | // LeftTopNear |
389 | aRes->myVertices[0] = SelectMgr_MatOp::Transform (theTrsf, myVertices[0]); |
390 | // LeftTopFar |
391 | aRes->myVertices[1] = SelectMgr_MatOp::Transform (theTrsf, myVertices[1]); |
392 | // LeftBottomNear |
393 | aRes->myVertices[2] = SelectMgr_MatOp::Transform (theTrsf, myVertices[2]); |
394 | // LeftBottomFar |
395 | aRes->myVertices[3] = SelectMgr_MatOp::Transform (theTrsf, myVertices[3]); |
396 | // RightTopNear |
397 | aRes->myVertices[4] = SelectMgr_MatOp::Transform (theTrsf, myVertices[4]); |
398 | // RightTopFar |
399 | aRes->myVertices[5] = SelectMgr_MatOp::Transform (theTrsf, myVertices[5]); |
400 | // RightBottomNear |
401 | aRes->myVertices[6] = SelectMgr_MatOp::Transform (theTrsf, myVertices[6]); |
402 | // RightBottomFar |
403 | aRes->myVertices[7] = SelectMgr_MatOp::Transform (theTrsf, myVertices[7]); |
404 | |
2157d6ac |
405 | // compute frustum normals |
406 | computeNormals (aRes->myVertices, aRes->myPlanes); |
28ee613b |
407 | |
408 | for (Standard_Integer aPlaneIdx = 0; aPlaneIdx < 6; ++aPlaneIdx) |
409 | { |
410 | Standard_Real aMax = -DBL_MAX; |
411 | Standard_Real aMin = DBL_MAX; |
412 | const SelectMgr_Vec3 aPlane = aRes->myPlanes[aPlaneIdx]; |
413 | for (Standard_Integer aVertIdx = 0; aVertIdx < 8; ++aVertIdx) |
414 | { |
415 | Standard_Real aProjection = DOT (aPlane, aRes->myVertices[aVertIdx]); |
416 | aMax = Max (aMax, aProjection); |
417 | aMin = Min (aMin, aProjection); |
418 | } |
419 | aRes->myMaxVertsProjections[aPlaneIdx] = aMax; |
420 | aRes->myMinVertsProjections[aPlaneIdx] = aMin; |
421 | } |
422 | |
423 | SelectMgr_Vec3 aDimensions[3] = |
424 | { |
425 | SelectMgr_Vec3 (1.0, 0.0, 0.0), |
426 | SelectMgr_Vec3 (0.0, 1.0, 0.0), |
427 | SelectMgr_Vec3 (0.0, 0.0, 1.0) |
428 | }; |
429 | |
430 | for (Standard_Integer aDim = 0; aDim < 3; ++aDim) |
431 | { |
432 | Standard_Real aMax = -DBL_MAX; |
433 | Standard_Real aMin = DBL_MAX; |
434 | for (Standard_Integer aVertIdx = 0; aVertIdx < 8; ++aVertIdx) |
435 | { |
436 | Standard_Real aProjection = DOT (aDimensions[aDim], aRes->myVertices[aVertIdx]); |
437 | aMax = Max (aMax, aProjection); |
438 | aMin = Min (aMin, aProjection); |
439 | } |
440 | aRes->myMaxOrthoVertsProjections[aDim] = aMax; |
441 | aRes->myMinOrthoVertsProjections[aDim] = aMin; |
442 | } |
443 | |
444 | // Horizontal |
445 | aRes->myEdgeDirs[0] = aRes->myVertices[4] - aRes->myVertices[0]; |
446 | // Vertical |
447 | aRes->myEdgeDirs[1] = aRes->myVertices[2] - aRes->myVertices[0]; |
448 | // LeftLower |
449 | aRes->myEdgeDirs[2] = aRes->myVertices[2] - aRes->myVertices[3]; |
450 | // RightLower |
451 | aRes->myEdgeDirs[3] = aRes->myVertices[6] - aRes->myVertices[7]; |
452 | // LeftUpper |
453 | aRes->myEdgeDirs[4] = aRes->myVertices[0] - aRes->myVertices[1]; |
454 | // RightUpper |
455 | aRes->myEdgeDirs[5] = aRes->myVertices[4] - aRes->myVertices[5]; |
456 | |
457 | return NCollection_Handle<SelectMgr_BaseFrustum> (aRes); |
458 | } |
459 | |
460 | // ======================================================================= |
461 | // function : Scale |
462 | // purpose : IMPORTANT: Makes sense only for frustum built on a single point! |
463 | // Returns a copy of the frustum resized according to the scale factor given |
464 | // ======================================================================= |
465 | NCollection_Handle<SelectMgr_BaseFrustum> SelectMgr_RectangularFrustum::Scale (const Standard_Real theScaleFactor) |
466 | { |
467 | SelectMgr_RectangularFrustum* aRes = new SelectMgr_RectangularFrustum(); |
468 | |
469 | aRes->myNearPickedPnt = myNearPickedPnt; |
470 | aRes->myFarPickedPnt = myFarPickedPnt; |
471 | aRes->myViewRayDir = myViewRayDir; |
472 | |
473 | aRes->myIsOrthographic = myIsOrthographic; |
474 | |
475 | // LeftTopNear |
476 | aRes->myVertices[0] = myBuilder->ProjectPntOnViewPlane (myMousePos.X() - theScaleFactor / 2.0, |
477 | myMousePos.Y() + theScaleFactor / 2.0, |
478 | 0.0); |
479 | // LeftTopFar |
480 | aRes->myVertices[1] = myBuilder->ProjectPntOnViewPlane (myMousePos.X() - theScaleFactor / 2.0, |
481 | myMousePos.Y() + theScaleFactor / 2.0, |
482 | 1.0); |
483 | // LeftBottomNear |
484 | aRes->myVertices[2] = myBuilder->ProjectPntOnViewPlane (myMousePos.X() - theScaleFactor / 2.0, |
485 | myMousePos.Y() - theScaleFactor / 2.0, |
486 | 0.0); |
487 | // LeftBottomFar |
488 | aRes->myVertices[3] = myBuilder->ProjectPntOnViewPlane (myMousePos.X() - theScaleFactor / 2.0, |
489 | myMousePos.Y() - theScaleFactor / 2.0, |
490 | 1.0); |
491 | // RightTopNear |
492 | aRes->myVertices[4] = myBuilder->ProjectPntOnViewPlane (myMousePos.X() + theScaleFactor / 2.0, |
493 | myMousePos.Y() + theScaleFactor / 2.0, |
494 | 0.0); |
495 | // RightTopFar |
496 | aRes->myVertices[5] = myBuilder->ProjectPntOnViewPlane (myMousePos.X() + theScaleFactor / 2.0, |
497 | myMousePos.Y() + theScaleFactor / 2.0, |
498 | 1.0); |
499 | // RightBottomNear |
500 | aRes->myVertices[6] = myBuilder->ProjectPntOnViewPlane (myMousePos.X() + theScaleFactor / 2.0, |
501 | myMousePos.Y() - theScaleFactor / 2.0, |
502 | 0.0); |
503 | // RightBottomFar |
504 | aRes->myVertices[7] = myBuilder->ProjectPntOnViewPlane (myMousePos.X() + theScaleFactor / 2.0, |
505 | myMousePos.Y() - theScaleFactor / 2.0, |
506 | 1.0); |
2157d6ac |
507 | // compute frustum normals |
508 | computeNormals (aRes->myVertices, aRes->myPlanes); |
f751596e |
509 | |
510 | for (Standard_Integer aPlaneIdx = 0; aPlaneIdx < 6; ++aPlaneIdx) |
511 | { |
512 | Standard_Real aMax = -DBL_MAX; |
513 | Standard_Real aMin = DBL_MAX; |
514 | const SelectMgr_Vec3 aPlane = aRes->myPlanes[aPlaneIdx]; |
515 | for (Standard_Integer aVertIdx = 0; aVertIdx < 8; ++aVertIdx) |
516 | { |
517 | Standard_Real aProjection = DOT (aPlane, aRes->myVertices[aVertIdx]); |
518 | aMax = Max (aMax, aProjection); |
519 | aMin = Min (aMin, aProjection); |
520 | } |
521 | aRes->myMaxVertsProjections[aPlaneIdx] = aMax; |
522 | aRes->myMinVertsProjections[aPlaneIdx] = aMin; |
523 | } |
524 | |
525 | SelectMgr_Vec3 aDimensions[3] = |
526 | { |
527 | SelectMgr_Vec3 (1.0, 0.0, 0.0), |
528 | SelectMgr_Vec3 (0.0, 1.0, 0.0), |
529 | SelectMgr_Vec3 (0.0, 0.0, 1.0) |
530 | }; |
531 | |
532 | for (Standard_Integer aDim = 0; aDim < 3; ++aDim) |
533 | { |
534 | Standard_Real aMax = -DBL_MAX; |
535 | Standard_Real aMin = DBL_MAX; |
536 | for (Standard_Integer aVertIdx = 0; aVertIdx < 8; ++aVertIdx) |
537 | { |
538 | Standard_Real aProjection = DOT (aDimensions[aDim], aRes->myVertices[aVertIdx]); |
539 | aMax = Max (aMax, aProjection); |
540 | aMin = Min (aMin, aProjection); |
541 | } |
542 | aRes->myMaxOrthoVertsProjections[aDim] = aMax; |
543 | aRes->myMinOrthoVertsProjections[aDim] = aMin; |
544 | } |
545 | |
546 | // Horizontal |
547 | aRes->myEdgeDirs[0] = aRes->myVertices[4] - aRes->myVertices[0]; |
548 | // Vertical |
549 | aRes->myEdgeDirs[1] = aRes->myVertices[2] - aRes->myVertices[0]; |
550 | // LeftLower |
551 | aRes->myEdgeDirs[2] = aRes->myVertices[2] - aRes->myVertices[3]; |
552 | // RightLower |
553 | aRes->myEdgeDirs[3] = aRes->myVertices[6] - aRes->myVertices[7]; |
554 | // LeftUpper |
555 | aRes->myEdgeDirs[4] = aRes->myVertices[0] - aRes->myVertices[1]; |
556 | // RightUpper |
557 | aRes->myEdgeDirs[5] = aRes->myVertices[4] - aRes->myVertices[5]; |
558 | |
559 | return NCollection_Handle<SelectMgr_BaseFrustum> (aRes); |
560 | } |
561 | |
562 | // ======================================================================= |
563 | // function : Overlaps |
564 | // purpose : Returns true if selecting volume is overlapped by |
565 | // axis-aligned bounding box with minimum corner at point |
566 | // theMinPnt and maximum at point theMaxPnt |
567 | // ======================================================================= |
2157d6ac |
568 | Standard_Boolean SelectMgr_RectangularFrustum::Overlaps (const SelectMgr_Vec3& theBoxMin, |
569 | const SelectMgr_Vec3& theBoxMax, |
570 | Standard_Boolean* theInside) |
f751596e |
571 | { |
2157d6ac |
572 | return hasOverlap (theBoxMin, theBoxMax, theInside); |
f751596e |
573 | } |
574 | |
575 | // ======================================================================= |
576 | // function : Overlaps |
577 | // purpose : SAT intersection test between defined volume and |
578 | // given axis-aligned box |
579 | // ======================================================================= |
7ab15952 |
580 | Standard_Boolean SelectMgr_RectangularFrustum::Overlaps (const BVH_Box<Standard_Real, 3>& theBox, |
581 | Standard_Real& theDepth) |
f751596e |
582 | { |
583 | const SelectMgr_Vec3& aMinPnt = theBox.CornerMin(); |
584 | const SelectMgr_Vec3& aMaxPnt = theBox.CornerMax(); |
585 | if (!hasOverlap (aMinPnt, aMaxPnt)) |
586 | return Standard_False; |
587 | |
588 | SelectMgr_Vec3 aNearestPnt = SelectMgr_Vec3 (RealLast(), RealLast(), RealLast()); |
589 | aNearestPnt.x() = Max (Min (myNearPickedPnt.x(), aMaxPnt.x()), aMinPnt.x()); |
590 | aNearestPnt.y() = Max (Min (myNearPickedPnt.y(), aMaxPnt.y()), aMinPnt.y()); |
591 | aNearestPnt.z() = Max (Min (myNearPickedPnt.z(), aMaxPnt.z()), aMinPnt.z()); |
592 | |
593 | theDepth = DISTANCE (aNearestPnt, myNearPickedPnt); |
594 | |
595 | return Standard_True; |
596 | } |
597 | |
598 | // ======================================================================= |
599 | // function : Overlaps |
600 | // purpose : Intersection test between defined volume and given point |
601 | // ======================================================================= |
7ab15952 |
602 | Standard_Boolean SelectMgr_RectangularFrustum::Overlaps (const gp_Pnt& thePnt, |
603 | Standard_Real& theDepth) |
f751596e |
604 | { |
605 | if (!hasOverlap (thePnt)) |
606 | return Standard_False; |
607 | |
608 | SelectMgr_Vec3 aPnt (thePnt.X(), thePnt.Y(), thePnt.Z()); |
609 | SelectMgr_Vec3 aV = aPnt - myNearPickedPnt; |
610 | SelectMgr_Vec3 aDetectedPnt = myNearPickedPnt + myViewRayDir * (DOT (aV, myViewRayDir) / DOT (myViewRayDir, myViewRayDir)); |
611 | |
612 | theDepth = DISTANCE (aDetectedPnt, myNearPickedPnt); |
613 | |
614 | return Standard_True; |
615 | } |
616 | |
617 | // ======================================================================= |
618 | // function : Overlaps |
619 | // purpose : Checks if line segment overlaps selecting frustum |
620 | // ======================================================================= |
7ab15952 |
621 | Standard_Boolean SelectMgr_RectangularFrustum::Overlaps (const gp_Pnt& thePnt1, |
622 | const gp_Pnt& thePnt2, |
623 | Standard_Real& theDepth) |
f751596e |
624 | { |
625 | theDepth = -DBL_MAX; |
626 | if (!hasOverlap (thePnt1, thePnt2)) |
627 | return Standard_False; |
628 | |
629 | segmentSegmentDistance (thePnt1, thePnt2, theDepth); |
630 | return Standard_True; |
631 | } |
632 | |
633 | // ======================================================================= |
634 | // function : Overlaps |
635 | // purpose : SAT intersection test between defined volume and given |
636 | // ordered set of points, representing line segments. The test |
637 | // may be considered of interior part or boundary line defined |
638 | // by segments depending on given sensitivity type |
639 | // ======================================================================= |
7ab15952 |
640 | Standard_Boolean SelectMgr_RectangularFrustum::Overlaps (const Handle(TColgp_HArray1OfPnt)& theArrayOfPnts, |
641 | Select3D_TypeOfSensitivity theSensType, |
642 | Standard_Real& theDepth) |
f751596e |
643 | { |
644 | if (theSensType == Select3D_TOS_BOUNDARY) |
645 | { |
646 | Standard_Integer aMatchingSegmentsNb = -1; |
647 | theDepth = DBL_MAX; |
648 | Standard_Integer aLower = theArrayOfPnts->Lower(); |
649 | Standard_Integer anUpper = theArrayOfPnts->Upper(); |
650 | |
651 | for (Standard_Integer aPntIter = aLower; aPntIter <= anUpper; ++aPntIter) |
652 | { |
653 | const gp_Pnt& aStartPnt = theArrayOfPnts->Value (aPntIter); |
654 | const gp_Pnt& aEndPnt = aPntIter == anUpper ? theArrayOfPnts->Value (aLower) |
655 | : theArrayOfPnts->Value (aPntIter + 1); |
656 | |
657 | if (hasOverlap (aStartPnt, aEndPnt)) |
658 | { |
659 | aMatchingSegmentsNb++; |
660 | Standard_Real aSegmentDepth = RealLast(); |
661 | segmentSegmentDistance (aStartPnt, aEndPnt, aSegmentDepth); |
662 | theDepth = Min (theDepth, aSegmentDepth); |
663 | } |
664 | } |
665 | |
666 | if (aMatchingSegmentsNb == -1) |
667 | return Standard_False; |
668 | } |
669 | else if (theSensType == Select3D_TOS_INTERIOR) |
670 | { |
671 | SelectMgr_Vec3 aPolyNorm (RealLast()); |
672 | if (!hasOverlap (theArrayOfPnts, aPolyNorm)) |
673 | return Standard_False; |
674 | |
675 | segmentPlaneIntersection (aPolyNorm, |
676 | theArrayOfPnts->Value (theArrayOfPnts->Lower()), |
677 | theDepth); |
678 | } |
679 | |
680 | return Standard_True; |
681 | } |
682 | |
683 | // ======================================================================= |
684 | // function : Overlaps |
685 | // purpose : SAT intersection test between defined volume and given |
686 | // triangle. The test may be considered of interior part or |
687 | // boundary line defined by triangle vertices depending on |
688 | // given sensitivity type |
689 | // ======================================================================= |
7ab15952 |
690 | Standard_Boolean SelectMgr_RectangularFrustum::Overlaps (const gp_Pnt& thePnt1, |
691 | const gp_Pnt& thePnt2, |
692 | const gp_Pnt& thePnt3, |
693 | Select3D_TypeOfSensitivity theSensType, |
694 | Standard_Real& theDepth) |
f751596e |
695 | { |
696 | if (theSensType == Select3D_TOS_BOUNDARY) |
697 | { |
698 | Handle(TColgp_HArray1OfPnt) aPntsArray = new TColgp_HArray1OfPnt(1, 4); |
699 | aPntsArray->SetValue (1, thePnt1); |
700 | aPntsArray->SetValue (2, thePnt2); |
701 | aPntsArray->SetValue (3, thePnt3); |
702 | aPntsArray->SetValue (4, thePnt1); |
703 | return Overlaps (aPntsArray, Select3D_TOS_BOUNDARY, theDepth); |
704 | } |
705 | else if (theSensType == Select3D_TOS_INTERIOR) |
706 | { |
707 | SelectMgr_Vec3 aTriangleNormal (RealLast()); |
708 | if (!hasOverlap (thePnt1, thePnt2, thePnt3, aTriangleNormal)) |
709 | return Standard_False; |
710 | |
711 | // check if intersection point belongs to triangle's interior part |
712 | SelectMgr_Vec3 aPnt1 (thePnt1.X(), thePnt1.Y(), thePnt1.Z()); |
713 | SelectMgr_Vec3 aTrEdges[3] = { SelectMgr_Vec3 (thePnt2.X() - thePnt1.X(), thePnt2.Y() - thePnt1.Y(), thePnt2.Z() - thePnt1.Z()), |
714 | SelectMgr_Vec3 (thePnt3.X() - thePnt2.X(), thePnt3.Y() - thePnt2.Y(), thePnt3.Z() - thePnt2.Z()), |
715 | SelectMgr_Vec3 (thePnt1.X() - thePnt3.X(), thePnt1.Y() - thePnt3.Y(), thePnt1.Z() - thePnt3.Z()) }; |
716 | SelectMgr_Vec3 anEdge = (aPnt1 - myNearPickedPnt) * (1.0 / DOT (aTriangleNormal, myViewRayDir)); |
717 | |
718 | Standard_Real aTime = DOT (aTriangleNormal, anEdge); |
719 | |
720 | SelectMgr_Vec3 aVec = SelectMgr_Vec3 (myViewRayDir.y() * anEdge.z() - myViewRayDir.z() * anEdge.y(), |
721 | myViewRayDir.z() * anEdge.x() - myViewRayDir.x() * anEdge.z(), |
722 | myViewRayDir.x() * anEdge.y() - myViewRayDir.y() * anEdge.x()); |
723 | |
724 | Standard_Real anU = DOT (aVec, aTrEdges[2]); |
725 | Standard_Real aV = DOT (aVec, aTrEdges[0]); |
726 | |
727 | Standard_Boolean isInterior = (aTime >= 0.0) && (anU >= 0.0) && (aV >= 0.0) && (anU + aV <= 1.0); |
728 | |
729 | if (isInterior) |
730 | { |
731 | SelectMgr_Vec3 aDetectedPnt = myNearPickedPnt + myViewRayDir * aTime; |
732 | theDepth = DISTANCE (myNearPickedPnt, aDetectedPnt); |
733 | return Standard_True; |
734 | } |
735 | |
736 | gp_Pnt aPnts[3] = {thePnt1, thePnt2, thePnt3}; |
737 | Standard_Real aMinDist = RealLast(); |
738 | Standard_Integer aNearestEdgeIdx = -1; |
739 | SelectMgr_Vec3 aPtOnPlane = myNearPickedPnt + myViewRayDir * aTime; |
740 | for (Standard_Integer anEdgeIdx = 0; anEdgeIdx < 3; ++anEdgeIdx) |
741 | { |
742 | SelectMgr_Vec3 aW = SelectMgr_Vec3 (aPtOnPlane.x() - aPnts[anEdgeIdx].X(), |
743 | aPtOnPlane.y() - aPnts[anEdgeIdx].Y(), |
744 | aPtOnPlane.z() - aPnts[anEdgeIdx].Z()); |
745 | Standard_Real aCoef = DOT (aTrEdges[anEdgeIdx], aW) / DOT (aTrEdges[anEdgeIdx], aTrEdges[anEdgeIdx]); |
746 | Standard_Real aDist = DISTANCE (aPtOnPlane, SelectMgr_Vec3 (aPnts[anEdgeIdx].X() + aCoef * aTrEdges[anEdgeIdx].x(), |
747 | aPnts[anEdgeIdx].Y() + aCoef * aTrEdges[anEdgeIdx].y(), |
748 | aPnts[anEdgeIdx].Z() + aCoef * aTrEdges[anEdgeIdx].z())); |
749 | if (aMinDist > aDist) |
750 | { |
751 | aMinDist = aDist; |
752 | aNearestEdgeIdx = anEdgeIdx; |
753 | } |
754 | } |
755 | segmentSegmentDistance (aPnts[aNearestEdgeIdx], aPnts[(aNearestEdgeIdx + 1) % 3], theDepth); |
756 | } |
757 | |
758 | return Standard_True; |
759 | } |
760 | |
761 | // ======================================================================= |
762 | // function : DistToGeometryCenter |
763 | // purpose : Measures distance between 3d projection of user-picked |
764 | // screen point and given point theCOG |
765 | // ======================================================================= |
7ab15952 |
766 | Standard_Real SelectMgr_RectangularFrustum::DistToGeometryCenter (const gp_Pnt& theCOG) |
f751596e |
767 | { |
768 | const SelectMgr_Vec3& aCOG = SelectMgr_Vec3 (theCOG.X(), theCOG.Y(), theCOG.Z()); |
769 | return DISTANCE (aCOG, myNearPickedPnt); |
770 | } |
771 | |
772 | // ======================================================================= |
773 | // function : DetectedPoint |
774 | // purpose : Calculates the point on a view ray that was detected during |
775 | // the run of selection algo by given depth |
776 | // ======================================================================= |
777 | SelectMgr_Vec3 SelectMgr_RectangularFrustum::DetectedPoint (const Standard_Real theDepth) const |
778 | { |
779 | return myNearPickedPnt + myViewRayDir * theDepth; |
780 | } |
781 | |
782 | // ======================================================================= |
783 | // function : IsClipped |
784 | // purpose : Checks if the point of sensitive in which selection was |
785 | // detected belongs to the region defined by clipping planes |
786 | // ======================================================================= |
7ab15952 |
787 | Standard_Boolean SelectMgr_RectangularFrustum::IsClipped (const Graphic3d_SequenceOfHClipPlane& thePlanes, |
788 | const Standard_Real theDepth) |
f751596e |
789 | { |
790 | Graphic3d_SequenceOfHClipPlane::Iterator aPlaneIt (thePlanes); |
791 | Standard_Real aMaxDepth = DBL_MAX; |
792 | Standard_Real aMinDepth = -DBL_MAX; |
793 | Standard_Real aPlaneA, aPlaneB, aPlaneC, aPlaneD; |
794 | for ( ; aPlaneIt.More(); aPlaneIt.Next()) |
795 | { |
796 | const Handle(Graphic3d_ClipPlane)& aClipPlane = aPlaneIt.Value(); |
797 | if (!aClipPlane->IsOn()) |
798 | continue; |
799 | |
800 | gp_Pln aGeomPlane = aClipPlane->ToPlane(); |
801 | |
802 | aGeomPlane.Coefficients (aPlaneA, aPlaneB, aPlaneC, aPlaneD); |
803 | |
804 | const gp_XYZ& aPlaneDirXYZ = aGeomPlane.Axis().Direction().XYZ(); |
805 | |
806 | Standard_Real aDotProduct = DOTp (myViewRayDir, aPlaneDirXYZ); |
807 | Standard_Real aDistance = - (DOTp (myNearPickedPnt, aPlaneDirXYZ) + aPlaneD); |
808 | |
809 | // check whether the pick line is parallel to clip plane |
810 | if (Abs (aDotProduct) < Precision::Angular()) |
811 | { |
812 | // line lies below the plane and is not clipped, skip |
813 | continue; |
814 | } |
815 | |
816 | // compute distance to point of pick line intersection with the plane |
817 | Standard_Real aParam = aDistance / aDotProduct; |
818 | |
819 | // check if ray intersects the plane, in case aIntDist < 0 |
820 | // the plane is "behind" the ray |
821 | if (aParam < 0.0) |
822 | { |
823 | continue; |
824 | } |
825 | |
826 | const SelectMgr_Vec3 anIntersectionPt = myNearPickedPnt + myViewRayDir * aParam; |
827 | const Standard_Real aDistToPln = DISTANCE (anIntersectionPt, myNearPickedPnt); |
828 | |
829 | // change depth limits for case of opposite and directed planes |
830 | if (aDotProduct < 0.0) |
831 | { |
832 | aMaxDepth = Min (aDistToPln, aMaxDepth); |
833 | } |
834 | else if (aDistToPln > aMinDepth) |
835 | { |
836 | aMinDepth = Max (aDistToPln, aMinDepth); |
837 | } |
838 | } |
839 | |
840 | return (theDepth <= aMinDepth || theDepth >= aMaxDepth); |
841 | } |