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 | |
e1eb39d2 |
16 | #include <SelectMgr_RectangularFrustum.hxx> |
17 | |
18 | #include <BVH_Tools.hxx> |
503374ad |
19 | #include <gp_Pln.hxx> |
f751596e |
20 | #include <NCollection_Vector.hxx> |
21 | #include <Poly_Array1OfTriangle.hxx> |
e1eb39d2 |
22 | #include <SelectMgr_FrustumBuilder.hxx> |
23 | #include <SelectMgr_ViewClipRange.hxx> |
f751596e |
24 | |
e1eb39d2 |
25 | // ======================================================================= |
26 | // function : Constructor |
27 | // purpose : |
28 | // ======================================================================= |
29 | SelectMgr_RectangularFrustum::SelectMgr_RectangularFrustum() |
30 | : myScale(1.0) |
31 | { |
32 | } |
f751596e |
33 | |
f751596e |
34 | // ======================================================================= |
35 | // function : segmentSegmentDistance |
36 | // purpose : |
37 | // ======================================================================= |
38 | void SelectMgr_RectangularFrustum::segmentSegmentDistance (const gp_Pnt& theSegPnt1, |
39 | const gp_Pnt& theSegPnt2, |
4a056d20 |
40 | SelectBasics_PickResult& thePickResult) const |
f751596e |
41 | { |
3bf9a45f |
42 | gp_XYZ anU = theSegPnt2.XYZ() - theSegPnt1.XYZ(); |
2ff1d580 |
43 | gp_XYZ aV = myFarPickedPnt.XYZ() - myNearPickedPnt.XYZ(); // use unnormalized vector instead of myViewRayDir to clip solutions behind Far plane |
3bf9a45f |
44 | gp_XYZ aW = theSegPnt1.XYZ() - myNearPickedPnt.XYZ(); |
45 | |
46 | Standard_Real anA = anU.Dot (anU); |
47 | Standard_Real aB = anU.Dot (aV); |
48 | Standard_Real aC = aV.Dot (aV); |
49 | Standard_Real aD = anU.Dot (aW); |
50 | Standard_Real anE = aV.Dot (aW); |
f751596e |
51 | Standard_Real aCoef = anA * aC - aB * aB; |
a52c06d5 |
52 | Standard_Real aSn = aCoef; |
f751596e |
53 | Standard_Real aTc, aTn, aTd = aCoef; |
54 | |
fe76088c |
55 | if (aCoef < gp::Resolution()) |
f751596e |
56 | { |
f751596e |
57 | aTn = anE; |
58 | aTd = aC; |
59 | } |
60 | else |
61 | { |
62 | aSn = (aB * anE - aC * aD); |
63 | aTn = (anA * anE - aB * aD); |
64 | if (aSn < 0.0) |
65 | { |
f751596e |
66 | aTn = anE; |
67 | aTd = aC; |
68 | } |
a52c06d5 |
69 | else if (aSn > aCoef) |
f751596e |
70 | { |
f751596e |
71 | aTn = anE + aB; |
72 | aTd = aC; |
73 | } |
74 | } |
75 | |
76 | if (aTn < 0.0) |
77 | { |
78 | aTn = 0.0; |
f751596e |
79 | } |
80 | else if (aTn > aTd) |
81 | { |
82 | aTn = aTd; |
f751596e |
83 | } |
fe76088c |
84 | aTc = (Abs (aTd) < gp::Resolution() ? 0.0 : aTn / aTd); |
f751596e |
85 | |
2ff1d580 |
86 | const gp_Pnt aClosestPnt = myNearPickedPnt.XYZ() + aV * aTc; |
17017555 |
87 | thePickResult.SetDepth (myNearPickedPnt.Distance (aClosestPnt) * myScale); |
88 | |
89 | const gp_Vec aPickedVec = aClosestPnt.XYZ() - theSegPnt1.XYZ(); |
90 | const gp_Vec aFigureVec = theSegPnt2.XYZ() - theSegPnt1.XYZ(); |
91 | const Standard_Real aPickedVecMod = aPickedVec.Magnitude(); |
92 | const Standard_Real aFigureVecMod = aFigureVec.Magnitude(); |
93 | if (aPickedVecMod <= gp::Resolution() |
94 | || aFigureVecMod <= gp::Resolution()) |
95 | { |
96 | thePickResult.SetPickedPoint (aClosestPnt); |
97 | return; |
98 | } |
99 | |
100 | const Standard_Real aCosOfAngle = aFigureVec.Dot (aPickedVec) / (aPickedVecMod * aFigureVecMod); |
101 | const Standard_Real aSegPntShift = Min(aFigureVecMod, Max(0.0, aCosOfAngle * aPickedVecMod)); |
102 | thePickResult.SetPickedPoint (theSegPnt1.XYZ() + aFigureVec.XYZ() * (aSegPntShift / aFigureVecMod)); |
f751596e |
103 | } |
104 | |
105 | // ======================================================================= |
106 | // function : segmentPlaneIntersection |
107 | // purpose : |
108 | // ======================================================================= |
17017555 |
109 | bool SelectMgr_RectangularFrustum::segmentPlaneIntersection (const gp_Vec& thePlane, |
f751596e |
110 | const gp_Pnt& thePntOnPlane, |
4a056d20 |
111 | SelectBasics_PickResult& thePickResult) const |
f751596e |
112 | { |
2ff1d580 |
113 | gp_XYZ anU = myFarPickedPnt.XYZ() - myNearPickedPnt.XYZ(); // use unnormalized vector instead of myViewRayDir to clip solutions behind Far plane by > 1.0 check |
3bf9a45f |
114 | gp_XYZ aW = myNearPickedPnt.XYZ() - thePntOnPlane.XYZ(); |
115 | Standard_Real aD = thePlane.Dot (anU); |
116 | Standard_Real aN = -thePlane.Dot (aW); |
f751596e |
117 | |
118 | if (Abs (aD) < Precision::Confusion()) |
119 | { |
120 | if (Abs (aN) < Precision::Angular()) |
121 | { |
17017555 |
122 | thePickResult.Invalidate(); |
123 | return false; |
f751596e |
124 | } |
125 | else |
126 | { |
17017555 |
127 | thePickResult.Invalidate(); |
128 | return false; |
f751596e |
129 | } |
130 | } |
131 | |
132 | Standard_Real aParam = aN / aD; |
2ff1d580 |
133 | if (aParam < 0.0 || aParam > 1.0) // > 1.0 check could be removed for an infinite ray and anU=myViewRayDir |
f751596e |
134 | { |
17017555 |
135 | thePickResult.Invalidate(); |
136 | return false; |
f751596e |
137 | } |
138 | |
3bf9a45f |
139 | gp_Pnt aClosestPnt = myNearPickedPnt.XYZ() + anU * aParam; |
17017555 |
140 | thePickResult.SetDepth (myNearPickedPnt.Distance (aClosestPnt) * myScale); |
141 | return true; |
f751596e |
142 | } |
143 | |
2157d6ac |
144 | namespace |
145 | { |
3bf9a45f |
146 | // ======================================================================= |
147 | // function : computeFrustum |
148 | // purpose : Computes base frustum data: its vertices and edge directions |
149 | // ======================================================================= |
150 | void computeFrustum (const gp_Pnt2d theMinPnt, const gp_Pnt2d& theMaxPnt, |
151 | const Handle(SelectMgr_FrustumBuilder)& theBuilder, |
152 | gp_Pnt* theVertices, gp_Vec* theEdges) |
153 | { |
154 | // LeftTopNear |
155 | theVertices[0] = theBuilder->ProjectPntOnViewPlane (theMinPnt.X(), |
156 | theMaxPnt.Y(), |
157 | 0.0); |
158 | // LeftTopFar |
159 | theVertices[1] = theBuilder->ProjectPntOnViewPlane (theMinPnt.X(), |
160 | theMaxPnt.Y(), |
161 | 1.0); |
162 | // LeftBottomNear |
163 | theVertices[2] = theBuilder->ProjectPntOnViewPlane (theMinPnt.X(), |
164 | theMinPnt.Y(), |
165 | 0.0); |
166 | // LeftBottomFar |
167 | theVertices[3] = theBuilder->ProjectPntOnViewPlane (theMinPnt.X(), |
168 | theMinPnt.Y(), |
169 | 1.0); |
170 | // RightTopNear |
171 | theVertices[4] = theBuilder->ProjectPntOnViewPlane (theMaxPnt.X(), |
172 | theMaxPnt.Y(), |
173 | 0.0); |
174 | // RightTopFar |
175 | theVertices[5] = theBuilder->ProjectPntOnViewPlane (theMaxPnt.X(), |
176 | theMaxPnt.Y(), |
177 | 1.0); |
178 | // RightBottomNear |
179 | theVertices[6] = theBuilder->ProjectPntOnViewPlane (theMaxPnt.X(), |
180 | theMinPnt.Y(), |
181 | 0.0); |
182 | // RightBottomFar |
183 | theVertices[7] = theBuilder->ProjectPntOnViewPlane (theMaxPnt.X(), |
184 | theMinPnt.Y(), |
185 | 1.0); |
186 | |
187 | // Horizontal |
188 | theEdges[0] = theVertices[4].XYZ() - theVertices[0].XYZ(); |
189 | // Vertical |
190 | theEdges[1] = theVertices[2].XYZ() - theVertices[0].XYZ(); |
191 | // LeftLower |
192 | theEdges[2] = theVertices[2].XYZ() - theVertices[3].XYZ(); |
193 | // RightLower |
194 | theEdges[3] = theVertices[6].XYZ() - theVertices[7].XYZ(); |
195 | // LeftUpper |
196 | theEdges[4] = theVertices[0].XYZ() - theVertices[1].XYZ(); |
197 | // RightUpper |
198 | theEdges[5] = theVertices[4].XYZ() - theVertices[5].XYZ(); |
199 | } |
200 | |
2157d6ac |
201 | // ======================================================================= |
202 | // function : computeNormals |
203 | // purpose : Computes normals to frustum faces |
204 | // ======================================================================= |
3bf9a45f |
205 | void computeNormals (const gp_Vec* theEdges, gp_Vec* theNormals) |
2157d6ac |
206 | { |
207 | // Top |
3bf9a45f |
208 | theNormals[0] = theEdges[0].Crossed (theEdges[4]); |
2157d6ac |
209 | // Bottom |
099f3513 |
210 | theNormals[1] = theEdges[2].Crossed (theEdges[0]); |
2157d6ac |
211 | // Left |
3bf9a45f |
212 | theNormals[2] = theEdges[4].Crossed (theEdges[1]); |
2157d6ac |
213 | // Right |
099f3513 |
214 | theNormals[3] = theEdges[1].Crossed (theEdges[5]); |
2157d6ac |
215 | // Near |
3bf9a45f |
216 | theNormals[4] = theEdges[0].Crossed (theEdges[1]); |
2157d6ac |
217 | // Far |
3bf9a45f |
218 | theNormals[5] = -theNormals[4]; |
2157d6ac |
219 | } |
220 | } |
221 | |
f751596e |
222 | // ======================================================================= |
3bf9a45f |
223 | // function : cacheVertexProjections |
224 | // purpose : Caches projection of frustum's vertices onto its plane directions |
225 | // and {i, j, k} |
f751596e |
226 | // ======================================================================= |
099f3513 |
227 | void SelectMgr_RectangularFrustum::cacheVertexProjections (SelectMgr_RectangularFrustum* theFrustum) const |
f751596e |
228 | { |
51d4a4f9 |
229 | if (theFrustum->Camera()->IsOrthographic()) |
f751596e |
230 | { |
3bf9a45f |
231 | // project vertices onto frustum normals |
232 | // Since orthographic view volume's faces are always a pairwise translation of |
233 | // one another, only 2 vertices that belong to opposite faces can be projected |
234 | // to simplify calculations. |
235 | Standard_Integer aVertIdxs[6] = { LeftTopNear, LeftBottomNear, // opposite planes in height direction |
236 | LeftBottomNear, RightBottomNear, // opposite planes in width direcion |
237 | LeftBottomFar, RightBottomNear }; // opposite planes in depth direction |
238 | for (Standard_Integer aPlaneIdx = 0; aPlaneIdx < 5; aPlaneIdx += 2) |
f751596e |
239 | { |
3bf9a45f |
240 | Standard_Real aProj1 = theFrustum->myPlanes[aPlaneIdx].XYZ().Dot (theFrustum->myVertices[aVertIdxs[aPlaneIdx]].XYZ()); |
241 | Standard_Real aProj2 = theFrustum->myPlanes[aPlaneIdx].XYZ().Dot (theFrustum->myVertices[aVertIdxs[aPlaneIdx + 1]].XYZ()); |
242 | theFrustum->myMinVertsProjections[aPlaneIdx] = Min (aProj1, aProj2); |
243 | theFrustum->myMaxVertsProjections[aPlaneIdx] = Max (aProj1, aProj2); |
f751596e |
244 | } |
f751596e |
245 | } |
3bf9a45f |
246 | else |
f751596e |
247 | { |
3bf9a45f |
248 | // project all vertices onto frustum normals |
249 | for (Standard_Integer aPlaneIdx = 0; aPlaneIdx < 6; ++aPlaneIdx) |
250 | { |
251 | Standard_Real aMax = -DBL_MAX; |
252 | Standard_Real aMin = DBL_MAX; |
253 | const gp_XYZ& aPlane = theFrustum->myPlanes[aPlaneIdx].XYZ(); |
254 | for (Standard_Integer aVertIdx = 0; aVertIdx < 8; ++aVertIdx) |
255 | { |
256 | Standard_Real aProjection = aPlane.Dot (theFrustum->myVertices[aVertIdx].XYZ()); |
257 | aMin = Min (aMin, aProjection); |
258 | aMax = Max (aMax, aProjection); |
259 | } |
260 | theFrustum->myMinVertsProjections[aPlaneIdx] = aMin; |
261 | theFrustum->myMaxVertsProjections[aPlaneIdx] = aMax; |
262 | } |
263 | } |
f751596e |
264 | |
3bf9a45f |
265 | // project vertices onto {i, j, k} |
f751596e |
266 | for (Standard_Integer aDim = 0; aDim < 3; ++aDim) |
267 | { |
268 | Standard_Real aMax = -DBL_MAX; |
3bf9a45f |
269 | Standard_Real aMin = DBL_MAX; |
f751596e |
270 | for (Standard_Integer aVertIdx = 0; aVertIdx < 8; ++aVertIdx) |
271 | { |
3bf9a45f |
272 | const gp_XYZ& aVert = theFrustum->myVertices[aVertIdx].XYZ(); |
273 | aMax = Max (aVert.GetData()[aDim], aMax); |
274 | aMin = Min (aVert.GetData()[aDim], aMin); |
f751596e |
275 | } |
3bf9a45f |
276 | theFrustum->myMaxOrthoVertsProjections[aDim] = aMax; |
277 | theFrustum->myMinOrthoVertsProjections[aDim] = aMin; |
f751596e |
278 | } |
3bf9a45f |
279 | } |
280 | |
281 | // ======================================================================= |
e1eb39d2 |
282 | // function : Init |
283 | // purpose : |
3bf9a45f |
284 | // ======================================================================= |
e1eb39d2 |
285 | void SelectMgr_RectangularFrustum::Init (const gp_Pnt2d &thePoint) |
3bf9a45f |
286 | { |
e1eb39d2 |
287 | mySelectionType = SelectMgr_SelectionType_Point; |
288 | mySelRectangle.SetMousePos (thePoint); |
289 | } |
7479f643 |
290 | |
e1eb39d2 |
291 | // ======================================================================= |
292 | // function : Init |
293 | // purpose : |
294 | // ======================================================================= |
295 | void SelectMgr_RectangularFrustum::Init (const gp_Pnt2d& theMinPnt, |
296 | const gp_Pnt2d& theMaxPnt) |
297 | { |
298 | mySelectionType = SelectMgr_SelectionType_Box; |
299 | mySelRectangle.SetMinPnt (theMinPnt); |
300 | mySelRectangle.SetMaxPnt (theMaxPnt); |
f751596e |
301 | } |
302 | |
303 | // ======================================================================= |
304 | // function : Build |
e1eb39d2 |
305 | // purpose : |
f751596e |
306 | // ======================================================================= |
e1eb39d2 |
307 | void SelectMgr_RectangularFrustum::Build() |
f751596e |
308 | { |
e1eb39d2 |
309 | Standard_ASSERT_RAISE (mySelectionType == SelectMgr_SelectionType_Point || mySelectionType == SelectMgr_SelectionType_Box, |
310 | "Error! SelectMgr_RectangularFrustum::Build() should be called after selection frustum initialization"); |
311 | gp_Pnt2d aMinPnt, aMaxPnt; |
312 | if (mySelectionType == SelectMgr_SelectionType_Point) |
313 | { |
314 | const gp_Pnt2d& aMousePos = mySelRectangle.MousePos(); |
315 | myNearPickedPnt = myBuilder->ProjectPntOnViewPlane (aMousePos.X(), aMousePos.Y(), 0.0); |
316 | myFarPickedPnt = myBuilder->ProjectPntOnViewPlane (aMousePos.X(), aMousePos.Y(), 1.0); |
317 | |
318 | aMinPnt.SetCoord (aMousePos.X() - myPixelTolerance * 0.5, |
319 | aMousePos.Y() - myPixelTolerance * 0.5); |
320 | aMaxPnt.SetCoord (aMousePos.X() + myPixelTolerance * 0.5, |
321 | aMousePos.Y() + myPixelTolerance * 0.5); |
322 | } |
323 | else |
324 | { |
325 | aMinPnt = mySelRectangle.MinPnt(); |
326 | aMaxPnt = mySelRectangle.MaxPnt(); |
327 | myNearPickedPnt = myBuilder->ProjectPntOnViewPlane ((aMinPnt.X() + aMaxPnt.X()) * 0.5, |
328 | (aMinPnt.Y() + aMaxPnt.Y()) * 0.5, |
329 | 0.0); |
330 | myFarPickedPnt = myBuilder->ProjectPntOnViewPlane ((aMinPnt.X() + aMaxPnt.X()) * 0.5, |
331 | (aMinPnt.Y() + aMaxPnt.Y()) * 0.5, |
332 | 1.0); |
333 | } |
334 | |
3bf9a45f |
335 | myViewRayDir = myFarPickedPnt.XYZ() - myNearPickedPnt.XYZ(); |
f751596e |
336 | |
3bf9a45f |
337 | // calculate base frustum characteristics: vertices and edge directions |
e1eb39d2 |
338 | computeFrustum (aMinPnt, aMaxPnt, myBuilder, myVertices, myEdgeDirs); |
f751596e |
339 | |
3bf9a45f |
340 | // compute frustum normals |
341 | computeNormals (myEdgeDirs, myPlanes); |
f751596e |
342 | |
3bf9a45f |
343 | // compute vertices projections onto frustum normals and |
344 | // {i, j, k} vectors and store them to corresponding class fields |
345 | cacheVertexProjections (this); |
7479f643 |
346 | |
347 | myScale = 1.0; |
f751596e |
348 | } |
349 | |
350 | // ======================================================================= |
3bf9a45f |
351 | // function : ScaleAndTransform |
352 | // purpose : IMPORTANT: Scaling makes sense only for frustum built on a single point! |
353 | // Note that this method does not perform any checks on type of the frustum. |
354 | // Returns a copy of the frustum resized according to the scale factor given |
355 | // and transforms it using the matrix given. |
356 | // There are no default parameters, but in case if: |
357 | // - transformation only is needed: @theScaleFactor must be initialized |
358 | // as any negative value; |
359 | // - scale only is needed: @theTrsf must be set to gp_Identity. |
f751596e |
360 | // ======================================================================= |
e1eb39d2 |
361 | Handle(SelectMgr_BaseIntersector) SelectMgr_RectangularFrustum::ScaleAndTransform (const Standard_Integer theScaleFactor, |
362 | const gp_GTrsf& theTrsf, |
363 | const Handle(SelectMgr_FrustumBuilder)& theBuilder) const |
f751596e |
364 | { |
e1eb39d2 |
365 | Standard_ASSERT_RAISE (mySelectionType == SelectMgr_SelectionType_Point || mySelectionType == SelectMgr_SelectionType_Box, |
366 | "Error! SelectMgr_RectangularFrustum::ScaleAndTransform() should be called after selection frustum initialization"); |
367 | |
0038de11 |
368 | Standard_ASSERT_RAISE (theScaleFactor >= 0, |
369 | "Error! Pixel tolerance for selection should not be negative"); |
3bf9a45f |
370 | |
099f3513 |
371 | Handle(SelectMgr_RectangularFrustum) aRes = new SelectMgr_RectangularFrustum(); |
3bf9a45f |
372 | const Standard_Boolean isToScale = theScaleFactor != 1; |
373 | const Standard_Boolean isToTrsf = theTrsf.Form() != gp_Identity; |
f751596e |
374 | |
3bf9a45f |
375 | if (!isToScale && !isToTrsf) |
e1eb39d2 |
376 | { |
377 | aRes->SetBuilder (theBuilder); |
3bf9a45f |
378 | return aRes; |
e1eb39d2 |
379 | } |
f751596e |
380 | |
51d4a4f9 |
381 | aRes->SetCamera (myCamera); |
099f3513 |
382 | const SelectMgr_RectangularFrustum* aRef = this; |
f751596e |
383 | |
3bf9a45f |
384 | if (isToScale) |
28ee613b |
385 | { |
3bf9a45f |
386 | aRes->myNearPickedPnt = myNearPickedPnt; |
387 | aRes->myFarPickedPnt = myFarPickedPnt; |
388 | aRes->myViewRayDir = myViewRayDir; |
28ee613b |
389 | |
e1eb39d2 |
390 | const gp_Pnt2d& aMousePos = mySelRectangle.MousePos(); |
391 | const gp_Pnt2d aMinPnt (aMousePos.X() - theScaleFactor * 0.5, |
392 | aMousePos.Y() - theScaleFactor * 0.5); |
393 | const gp_Pnt2d aMaxPnt (aMousePos.X() + theScaleFactor * 0.5, |
394 | aMousePos.Y() + theScaleFactor * 0.5); |
28ee613b |
395 | |
3bf9a45f |
396 | // recompute base frustum characteristics from scratch |
397 | computeFrustum (aMinPnt, aMaxPnt, myBuilder, aRes->myVertices, aRes->myEdgeDirs); |
f751596e |
398 | |
099f3513 |
399 | aRef = aRes.get(); |
f751596e |
400 | } |
401 | |
3bf9a45f |
402 | if (isToTrsf) |
f751596e |
403 | { |
91d96372 |
404 | const Standard_Real aRefScale = aRef->myFarPickedPnt.SquareDistance (aRef->myNearPickedPnt); |
405 | |
406 | gp_Pnt aPoint = aRef->myNearPickedPnt; |
407 | theTrsf.Transforms (aPoint.ChangeCoord()); |
408 | aRes->myNearPickedPnt = aPoint; |
409 | |
410 | aPoint.SetXYZ (aRef->myFarPickedPnt.XYZ()); |
411 | theTrsf.Transforms (aPoint.ChangeCoord()); |
412 | aRes->myFarPickedPnt = aPoint; |
413 | |
2ff1d580 |
414 | aRes->myViewRayDir = aRes->myFarPickedPnt.XYZ() - aRes->myNearPickedPnt.XYZ(); |
3bf9a45f |
415 | |
91d96372 |
416 | for (Standard_Integer anIt = 0; anIt < 8; anIt++) |
417 | { |
418 | aPoint = aRef->myVertices[anIt]; |
419 | theTrsf.Transforms (aPoint.ChangeCoord()); |
420 | aRes->myVertices[anIt] = aPoint; |
421 | } |
3bf9a45f |
422 | |
423 | // Horizontal |
424 | aRes->myEdgeDirs[0] = aRes->myVertices[4].XYZ() - aRes->myVertices[0].XYZ(); |
425 | // Vertical |
426 | aRes->myEdgeDirs[1] = aRes->myVertices[2].XYZ() - aRes->myVertices[0].XYZ(); |
427 | // LeftLower |
428 | aRes->myEdgeDirs[2] = aRes->myVertices[2].XYZ() - aRes->myVertices[3].XYZ(); |
429 | // RightLower |
430 | aRes->myEdgeDirs[3] = aRes->myVertices[6].XYZ() - aRes->myVertices[7].XYZ(); |
431 | // LeftUpper |
432 | aRes->myEdgeDirs[4] = aRes->myVertices[0].XYZ() - aRes->myVertices[1].XYZ(); |
433 | // RightUpper |
434 | aRes->myEdgeDirs[5] = aRes->myVertices[4].XYZ() - aRes->myVertices[5].XYZ(); |
7479f643 |
435 | |
91d96372 |
436 | // Compute scale to transform depth from local coordinate system to world coordinate system |
437 | aRes->myScale = Sqrt (aRefScale / aRes->myFarPickedPnt.SquareDistance (aRes->myNearPickedPnt)); |
f751596e |
438 | } |
439 | |
51d4a4f9 |
440 | aRes->SetBuilder (theBuilder); |
441 | |
3bf9a45f |
442 | // compute frustum normals |
443 | computeNormals (aRes->myEdgeDirs, aRes->myPlanes); |
444 | |
099f3513 |
445 | cacheVertexProjections (aRes.get()); |
f751596e |
446 | |
e1eb39d2 |
447 | aRes->mySelectionType = mySelectionType; |
448 | aRes->mySelRectangle = mySelRectangle; |
099f3513 |
449 | return aRes; |
f751596e |
450 | } |
451 | |
e1eb39d2 |
452 | // ======================================================================= |
453 | // function : IsScalable |
454 | // purpose : |
455 | // ======================================================================= |
456 | Standard_Boolean SelectMgr_RectangularFrustum::IsScalable() const |
457 | { |
458 | return mySelectionType == SelectMgr_SelectionType_Point; |
459 | } |
460 | |
f751596e |
461 | // ======================================================================= |
03c9cc86 |
462 | // function : OverlapsBox |
f751596e |
463 | // purpose : Returns true if selecting volume is overlapped by |
464 | // axis-aligned bounding box with minimum corner at point |
465 | // theMinPnt and maximum at point theMaxPnt |
466 | // ======================================================================= |
03c9cc86 |
467 | Standard_Boolean SelectMgr_RectangularFrustum::OverlapsBox (const SelectMgr_Vec3& theBoxMin, |
468 | const SelectMgr_Vec3& theBoxMax, |
469 | Standard_Boolean* theInside) const |
f751596e |
470 | { |
e1eb39d2 |
471 | Standard_ASSERT_RAISE(mySelectionType == SelectMgr_SelectionType_Point || mySelectionType == SelectMgr_SelectionType_Box, |
472 | "Error! SelectMgr_RectangularFrustum::Overlaps() should be called after selection frustum initialization"); |
473 | |
03c9cc86 |
474 | return hasBoxOverlap (theBoxMin, theBoxMax, theInside); |
f751596e |
475 | } |
476 | |
477 | // ======================================================================= |
03c9cc86 |
478 | // function : OverlapsBox |
f751596e |
479 | // purpose : SAT intersection test between defined volume and |
480 | // given axis-aligned box |
481 | // ======================================================================= |
03c9cc86 |
482 | Standard_Boolean SelectMgr_RectangularFrustum::OverlapsBox (const SelectMgr_Vec3& theBoxMin, |
483 | const SelectMgr_Vec3& theBoxMax, |
484 | const SelectMgr_ViewClipRange& theClipRange, |
485 | SelectBasics_PickResult& thePickResult) const |
f751596e |
486 | { |
e1eb39d2 |
487 | Standard_ASSERT_RAISE(mySelectionType == SelectMgr_SelectionType_Point || mySelectionType == SelectMgr_SelectionType_Box, |
488 | "Error! SelectMgr_RectangularFrustum::Overlaps() should be called after selection frustum initialization"); |
489 | |
03c9cc86 |
490 | if (!hasBoxOverlap (theBoxMin, theBoxMax)) |
f751596e |
491 | return Standard_False; |
492 | |
d31fb73a |
493 | Standard_Real aDepth = 0.0; |
e1eb39d2 |
494 | BVH_Ray<Standard_Real, 3> aRay(SelectMgr_Vec3(myNearPickedPnt.X(), myNearPickedPnt.Y(), myNearPickedPnt.Z()), |
495 | SelectMgr_Vec3(myViewRayDir.X(), myViewRayDir.Y(), myViewRayDir.Z())); |
496 | Standard_Real aTimeEnter, aTimeLeave; |
497 | if (!BVH_Tools<Standard_Real, 3>::RayBoxIntersection (aRay, theBoxMin, theBoxMax, aTimeEnter, aTimeLeave)) |
d31fb73a |
498 | { |
499 | gp_Pnt aNearestPnt (RealLast(), RealLast(), RealLast()); |
500 | aNearestPnt.SetX (Max (Min (myNearPickedPnt.X(), theBoxMax.x()), theBoxMin.x())); |
501 | aNearestPnt.SetY (Max (Min (myNearPickedPnt.Y(), theBoxMax.y()), theBoxMin.y())); |
502 | aNearestPnt.SetZ (Max (Min (myNearPickedPnt.Z(), theBoxMax.z()), theBoxMin.z())); |
503 | |
504 | aDepth = aNearestPnt.Distance (myNearPickedPnt); |
505 | thePickResult.SetDepth (aDepth); |
d7fa57a7 |
506 | return !theClipRange.IsClipped (thePickResult.Depth()); |
d31fb73a |
507 | } |
508 | |
e1eb39d2 |
509 | Bnd_Range aRange(Max (aTimeEnter, 0.0), aTimeLeave); |
510 | aRange.GetMin (aDepth); |
511 | |
d7fa57a7 |
512 | if (!theClipRange.GetNearestDepth (aRange, aDepth)) |
d31fb73a |
513 | { |
514 | return Standard_False; |
515 | } |
f751596e |
516 | |
d31fb73a |
517 | thePickResult.SetDepth (aDepth); |
f751596e |
518 | |
d31fb73a |
519 | return Standard_True; |
f751596e |
520 | } |
521 | |
522 | // ======================================================================= |
03c9cc86 |
523 | // function : OverlapsPoint |
f751596e |
524 | // purpose : Intersection test between defined volume and given point |
525 | // ======================================================================= |
03c9cc86 |
526 | Standard_Boolean SelectMgr_RectangularFrustum::OverlapsPoint (const gp_Pnt& thePnt, |
527 | const SelectMgr_ViewClipRange& theClipRange, |
528 | SelectBasics_PickResult& thePickResult) const |
f751596e |
529 | { |
e1eb39d2 |
530 | Standard_ASSERT_RAISE(mySelectionType == SelectMgr_SelectionType_Point || mySelectionType == SelectMgr_SelectionType_Box, |
531 | "Error! SelectMgr_RectangularFrustum::Overlaps() should be called after selection frustum initialization"); |
532 | |
03c9cc86 |
533 | if (!hasPointOverlap (thePnt)) |
f751596e |
534 | return Standard_False; |
535 | |
3bf9a45f |
536 | gp_XYZ aV = thePnt.XYZ() - myNearPickedPnt.XYZ(); |
2ff1d580 |
537 | const Standard_Real aDepth = aV.Dot (myViewRayDir.XYZ()); |
f751596e |
538 | |
2ff1d580 |
539 | thePickResult.SetDepth (Abs (aDepth) * myScale); |
17017555 |
540 | thePickResult.SetPickedPoint (thePnt); |
f751596e |
541 | |
d7fa57a7 |
542 | return !theClipRange.IsClipped (thePickResult.Depth()); |
f751596e |
543 | } |
544 | |
3bf9a45f |
545 | // ======================================================================= |
03c9cc86 |
546 | // function : OverlapsPoint |
3bf9a45f |
547 | // purpose : Intersection test between defined volume and given point |
548 | // ======================================================================= |
03c9cc86 |
549 | Standard_Boolean SelectMgr_RectangularFrustum::OverlapsPoint (const gp_Pnt& thePnt) const |
3bf9a45f |
550 | { |
e1eb39d2 |
551 | Standard_ASSERT_RAISE(mySelectionType == SelectMgr_SelectionType_Point || mySelectionType == SelectMgr_SelectionType_Box, |
552 | "Error! SelectMgr_RectangularFrustum::Overlaps() should be called after selection frustum initialization"); |
553 | |
03c9cc86 |
554 | return hasPointOverlap (thePnt); |
3bf9a45f |
555 | } |
556 | |
f751596e |
557 | // ======================================================================= |
03c9cc86 |
558 | // function : OverlapsSegment |
f751596e |
559 | // purpose : Checks if line segment overlaps selecting frustum |
560 | // ======================================================================= |
03c9cc86 |
561 | Standard_Boolean SelectMgr_RectangularFrustum::OverlapsSegment (const gp_Pnt& thePnt1, |
562 | const gp_Pnt& thePnt2, |
563 | const SelectMgr_ViewClipRange& theClipRange, |
564 | SelectBasics_PickResult& thePickResult) const |
f751596e |
565 | { |
e1eb39d2 |
566 | Standard_ASSERT_RAISE(mySelectionType == SelectMgr_SelectionType_Point || mySelectionType == SelectMgr_SelectionType_Box, |
567 | "Error! SelectMgr_RectangularFrustum::Overlaps() should be called after selection frustum initialization"); |
568 | |
03c9cc86 |
569 | if (!hasSegmentOverlap (thePnt1, thePnt2)) |
f751596e |
570 | return Standard_False; |
571 | |
17017555 |
572 | segmentSegmentDistance (thePnt1, thePnt2, thePickResult); |
e9312c0f |
573 | |
d7fa57a7 |
574 | return !theClipRange.IsClipped (thePickResult.Depth()); |
f751596e |
575 | } |
576 | |
577 | // ======================================================================= |
03c9cc86 |
578 | // function : OverlapsPolygon |
f751596e |
579 | // purpose : SAT intersection test between defined volume and given |
580 | // ordered set of points, representing line segments. The test |
581 | // may be considered of interior part or boundary line defined |
582 | // by segments depending on given sensitivity type |
583 | // ======================================================================= |
03c9cc86 |
584 | Standard_Boolean SelectMgr_RectangularFrustum::OverlapsPolygon (const TColgp_Array1OfPnt& theArrayOfPnts, |
585 | Select3D_TypeOfSensitivity theSensType, |
586 | const SelectMgr_ViewClipRange& theClipRange, |
587 | SelectBasics_PickResult& thePickResult) const |
f751596e |
588 | { |
e1eb39d2 |
589 | Standard_ASSERT_RAISE(mySelectionType == SelectMgr_SelectionType_Point || mySelectionType == SelectMgr_SelectionType_Box, |
590 | "Error! SelectMgr_RectangularFrustum::Overlaps() should be called after selection frustum initialization"); |
591 | |
f751596e |
592 | if (theSensType == Select3D_TOS_BOUNDARY) |
593 | { |
594 | Standard_Integer aMatchingSegmentsNb = -1; |
17017555 |
595 | SelectBasics_PickResult aPickResult; |
596 | thePickResult.Invalidate(); |
114b7bf1 |
597 | const Standard_Integer aLower = theArrayOfPnts.Lower(); |
598 | const Standard_Integer anUpper = theArrayOfPnts.Upper(); |
f751596e |
599 | for (Standard_Integer aPntIter = aLower; aPntIter <= anUpper; ++aPntIter) |
600 | { |
114b7bf1 |
601 | const gp_Pnt& aStartPnt = theArrayOfPnts.Value (aPntIter); |
602 | const gp_Pnt& aEndPnt = theArrayOfPnts.Value (aPntIter == anUpper ? aLower : (aPntIter + 1)); |
03c9cc86 |
603 | if (hasSegmentOverlap (aStartPnt, aEndPnt)) |
f751596e |
604 | { |
605 | aMatchingSegmentsNb++; |
17017555 |
606 | segmentSegmentDistance (aStartPnt, aEndPnt, aPickResult); |
607 | thePickResult = SelectBasics_PickResult::Min (thePickResult, aPickResult); |
f751596e |
608 | } |
609 | } |
610 | |
611 | if (aMatchingSegmentsNb == -1) |
612 | return Standard_False; |
613 | } |
614 | else if (theSensType == Select3D_TOS_INTERIOR) |
615 | { |
3bf9a45f |
616 | gp_Vec aPolyNorm (gp_XYZ (RealLast(), RealLast(), RealLast())); |
03c9cc86 |
617 | if (!hasPolygonOverlap (theArrayOfPnts, aPolyNorm)) |
1ccc1371 |
618 | { |
619 | return Standard_False; |
620 | } |
621 | |
622 | if (aPolyNorm.Magnitude() <= Precision::Confusion()) |
623 | { |
624 | // treat degenerated polygon as point |
03c9cc86 |
625 | return OverlapsPoint (theArrayOfPnts.First(), theClipRange, thePickResult); |
1ccc1371 |
626 | } |
627 | else if (!segmentPlaneIntersection (aPolyNorm, theArrayOfPnts.First(), thePickResult)) |
17017555 |
628 | { |
f751596e |
629 | return Standard_False; |
17017555 |
630 | } |
f751596e |
631 | } |
632 | |
d7fa57a7 |
633 | return !theClipRange.IsClipped (thePickResult.Depth()); |
f751596e |
634 | } |
635 | |
636 | // ======================================================================= |
03c9cc86 |
637 | // function : OverlapsTriangle |
f751596e |
638 | // purpose : SAT intersection test between defined volume and given |
639 | // triangle. The test may be considered of interior part or |
640 | // boundary line defined by triangle vertices depending on |
641 | // given sensitivity type |
642 | // ======================================================================= |
03c9cc86 |
643 | Standard_Boolean SelectMgr_RectangularFrustum::OverlapsTriangle (const gp_Pnt& thePnt1, |
644 | const gp_Pnt& thePnt2, |
645 | const gp_Pnt& thePnt3, |
646 | Select3D_TypeOfSensitivity theSensType, |
647 | const SelectMgr_ViewClipRange& theClipRange, |
648 | SelectBasics_PickResult& thePickResult) const |
f751596e |
649 | { |
e1eb39d2 |
650 | Standard_ASSERT_RAISE(mySelectionType == SelectMgr_SelectionType_Point || mySelectionType == SelectMgr_SelectionType_Box, |
651 | "Error! SelectMgr_RectangularFrustum::Overlaps() should be called after selection frustum initialization"); |
652 | |
f751596e |
653 | if (theSensType == Select3D_TOS_BOUNDARY) |
654 | { |
114b7bf1 |
655 | const gp_Pnt aPntsArrayBuf[4] = { thePnt1, thePnt2, thePnt3, thePnt1 }; |
656 | const TColgp_Array1OfPnt aPntsArray (aPntsArrayBuf[0], 1, 4); |
03c9cc86 |
657 | return OverlapsPolygon (aPntsArray, Select3D_TOS_BOUNDARY, theClipRange, thePickResult); |
f751596e |
658 | } |
659 | else if (theSensType == Select3D_TOS_INTERIOR) |
660 | { |
3bf9a45f |
661 | gp_Vec aTriangleNormal (gp_XYZ (RealLast(), RealLast(), RealLast())); |
03c9cc86 |
662 | if (!hasTriangleOverlap (thePnt1, thePnt2, thePnt3, aTriangleNormal)) |
2ff1d580 |
663 | { |
f751596e |
664 | return Standard_False; |
2ff1d580 |
665 | } |
f751596e |
666 | |
2ff1d580 |
667 | const gp_XYZ aTrEdges[3] = { thePnt2.XYZ() - thePnt1.XYZ(), |
668 | thePnt3.XYZ() - thePnt2.XYZ(), |
669 | thePnt1.XYZ() - thePnt3.XYZ() }; |
670 | if (aTriangleNormal.SquareMagnitude() < gp::Resolution()) |
671 | { |
672 | // consider degenerated triangle as point or segment |
673 | return aTrEdges[0].SquareModulus() > gp::Resolution() |
03c9cc86 |
674 | ? OverlapsSegment (thePnt1, thePnt2, theClipRange, thePickResult) |
2ff1d580 |
675 | : (aTrEdges[1].SquareModulus() > gp::Resolution() |
03c9cc86 |
676 | ? OverlapsSegment (thePnt2, thePnt3, theClipRange, thePickResult) |
677 | : OverlapsPoint (thePnt1, theClipRange, thePickResult)); |
2ff1d580 |
678 | } |
7e17e8f0 |
679 | |
2ff1d580 |
680 | const gp_Pnt aPnts[3] = {thePnt1, thePnt2, thePnt3}; |
681 | const Standard_Real anAlpha = aTriangleNormal.XYZ().Dot (myViewRayDir.XYZ()); |
7e17e8f0 |
682 | if (Abs (anAlpha) < gp::Resolution()) |
683 | { |
2ff1d580 |
684 | // handle the case when triangle normal and selecting frustum direction are orthogonal |
685 | SelectBasics_PickResult aPickResult; |
686 | thePickResult.Invalidate(); |
687 | for (Standard_Integer anEdgeIter = 0; anEdgeIter < 3; ++anEdgeIter) |
7e17e8f0 |
688 | { |
2ff1d580 |
689 | const gp_Pnt& aStartPnt = aPnts[anEdgeIter]; |
690 | const gp_Pnt& anEndPnt = aPnts[anEdgeIter < 2 ? anEdgeIter + 1 : 0]; |
691 | segmentSegmentDistance (aStartPnt, anEndPnt, aPickResult); |
692 | thePickResult = SelectBasics_PickResult::Min (thePickResult, aPickResult); |
7e17e8f0 |
693 | } |
cece953c |
694 | thePickResult.SetSurfaceNormal (aTriangleNormal); |
d7fa57a7 |
695 | return !theClipRange.IsClipped (thePickResult.Depth()); |
7e17e8f0 |
696 | } |
697 | |
2ff1d580 |
698 | // check if intersection point belongs to triangle's interior part |
699 | const gp_XYZ anEdge = (thePnt1.XYZ() - myNearPickedPnt.XYZ()) * (1.0 / anAlpha); |
f751596e |
700 | |
2ff1d580 |
701 | const Standard_Real aTime = aTriangleNormal.Dot (anEdge); |
702 | const gp_XYZ aVec = myViewRayDir.XYZ().Crossed (anEdge); |
703 | const Standard_Real anU = aVec.Dot (aTrEdges[2]); |
704 | const Standard_Real aV = aVec.Dot (aTrEdges[0]); |
f751596e |
705 | |
17017555 |
706 | const Standard_Boolean isInterior = (aTime >= 0.0) && (anU >= 0.0) && (aV >= 0.0) && (anU + aV <= 1.0); |
707 | const gp_Pnt aPtOnPlane = myNearPickedPnt.XYZ() + myViewRayDir.XYZ() * aTime; |
f751596e |
708 | if (isInterior) |
709 | { |
17017555 |
710 | thePickResult.SetDepth (myNearPickedPnt.Distance (aPtOnPlane) * myScale); |
711 | thePickResult.SetPickedPoint (aPtOnPlane); |
2615c2d7 |
712 | thePickResult.SetSurfaceNormal (aTriangleNormal); |
d7fa57a7 |
713 | return !theClipRange.IsClipped (thePickResult.Depth()); |
f751596e |
714 | } |
715 | |
f751596e |
716 | Standard_Real aMinDist = RealLast(); |
2ff1d580 |
717 | Standard_Integer aNearestEdgeIdx1 = -1; |
f751596e |
718 | for (Standard_Integer anEdgeIdx = 0; anEdgeIdx < 3; ++anEdgeIdx) |
719 | { |
3bf9a45f |
720 | gp_XYZ aW = aPtOnPlane.XYZ() - aPnts[anEdgeIdx].XYZ(); |
721 | Standard_Real aCoef = aTrEdges[anEdgeIdx].Dot (aW) / aTrEdges[anEdgeIdx].Dot (aTrEdges[anEdgeIdx]); |
722 | Standard_Real aDist = aPtOnPlane.Distance (aPnts[anEdgeIdx].XYZ() + aCoef * aTrEdges[anEdgeIdx]); |
2ff1d580 |
723 | if (aDist < aMinDist) |
f751596e |
724 | { |
725 | aMinDist = aDist; |
2ff1d580 |
726 | aNearestEdgeIdx1 = anEdgeIdx; |
f751596e |
727 | } |
728 | } |
2ff1d580 |
729 | Standard_Integer aNearestEdgeIdx2 = (aNearestEdgeIdx1 + 1) % 3; |
6eeb528c |
730 | const gp_Vec aVec12 (aPnts[aNearestEdgeIdx1], aPnts[aNearestEdgeIdx2]); |
731 | if (aVec12.SquareMagnitude() > gp::Resolution() |
732 | && myViewRayDir.IsParallel (aVec12, Precision::Angular())) |
2ff1d580 |
733 | { |
734 | aNearestEdgeIdx2 = aNearestEdgeIdx1 == 0 ? 2 : aNearestEdgeIdx1 - 1; |
735 | } |
736 | segmentSegmentDistance (aPnts[aNearestEdgeIdx1], aPnts[aNearestEdgeIdx2], thePickResult); |
cece953c |
737 | thePickResult.SetSurfaceNormal (aTriangleNormal); |
f751596e |
738 | } |
739 | |
d7fa57a7 |
740 | return !theClipRange.IsClipped (thePickResult.Depth()); |
f751596e |
741 | } |
742 | |
e1eb39d2 |
743 | // ======================================================================= |
744 | // function : GetMousePosition |
745 | // purpose : |
746 | // ======================================================================= |
747 | const gp_Pnt2d& SelectMgr_RectangularFrustum::GetMousePosition() const |
748 | { |
749 | if (mySelectionType == SelectMgr_SelectionType_Point) |
750 | { |
751 | return mySelRectangle.MousePos(); |
752 | } |
753 | return base_type::GetMousePosition(); |
503374ad |
754 | } |
755 | |
756 | // ======================================================================= |
757 | // function : OverlapsSphere |
758 | // purpose : |
759 | // ======================================================================= |
760 | Standard_Boolean SelectMgr_RectangularFrustum::OverlapsSphere (const gp_Pnt& theCenter, |
761 | const Standard_Real theRadius, |
762 | const SelectMgr_ViewClipRange& theClipRange, |
763 | SelectBasics_PickResult& thePickResult) const |
764 | { |
765 | Standard_ASSERT_RAISE (mySelectionType == SelectMgr_SelectionType_Point || mySelectionType == SelectMgr_SelectionType_Box, |
766 | "Error! SelectMgr_RectangularFrustum::Overlaps() should be called after selection frustum initialization"); |
503374ad |
767 | Standard_Real aTimeEnter = 0.0, aTimeLeave = 0.0; |
768 | if (!RaySphereIntersection (theCenter, theRadius, myNearPickedPnt, myViewRayDir, aTimeEnter, aTimeLeave)) |
769 | { |
770 | return Standard_False; |
771 | } |
772 | |
773 | thePickResult.SetDepth (aTimeEnter * myScale); |
774 | if (theClipRange.IsClipped (thePickResult.Depth())) |
775 | { |
776 | thePickResult.SetDepth (aTimeLeave * myScale); |
777 | } |
a3b2aaef |
778 | gp_Pnt aPntOnSphere (myNearPickedPnt.XYZ() + myViewRayDir.XYZ() * thePickResult.Depth() / myScale); |
503374ad |
779 | gp_Vec aNormal (aPntOnSphere.XYZ() - theCenter.XYZ()); |
780 | thePickResult.SetPickedPoint (aPntOnSphere); |
781 | thePickResult.SetSurfaceNormal (aNormal); |
782 | return !theClipRange.IsClipped (thePickResult.Depth()); |
783 | } |
784 | |
785 | // ======================================================================= |
786 | // function : OverlapsSphere |
787 | // purpose : |
788 | // ======================================================================= |
789 | Standard_Boolean SelectMgr_RectangularFrustum::OverlapsSphere (const gp_Pnt& theCenter, |
790 | const Standard_Real theRadius, |
791 | Standard_Boolean* theInside) const |
792 | { |
793 | Standard_ASSERT_RAISE (mySelectionType == SelectMgr_SelectionType_Point || mySelectionType == SelectMgr_SelectionType_Box, |
794 | "Error! SelectMgr_RectangularFrustum::Overlaps() should be called after selection frustum initialization"); |
795 | return hasSphereOverlap (theCenter, theRadius, theInside); |
e1eb39d2 |
796 | } |
797 | |
f751596e |
798 | // ======================================================================= |
799 | // function : DistToGeometryCenter |
800 | // purpose : Measures distance between 3d projection of user-picked |
801 | // screen point and given point theCOG |
802 | // ======================================================================= |
4a056d20 |
803 | Standard_Real SelectMgr_RectangularFrustum::DistToGeometryCenter (const gp_Pnt& theCOG) const |
f751596e |
804 | { |
e1eb39d2 |
805 | Standard_ASSERT_RAISE(mySelectionType == SelectMgr_SelectionType_Point || mySelectionType == SelectMgr_SelectionType_Box, |
806 | "Error! SelectMgr_RectangularFrustum::DistToGeometryCenter() should be called after selection frustum initialization"); |
807 | |
7479f643 |
808 | return theCOG.Distance (myNearPickedPnt) * myScale; |
f751596e |
809 | } |
810 | |
811 | // ======================================================================= |
812 | // function : DetectedPoint |
813 | // purpose : Calculates the point on a view ray that was detected during |
814 | // the run of selection algo by given depth |
815 | // ======================================================================= |
3bf9a45f |
816 | gp_Pnt SelectMgr_RectangularFrustum::DetectedPoint (const Standard_Real theDepth) const |
f751596e |
817 | { |
e1eb39d2 |
818 | Standard_ASSERT_RAISE (mySelectionType == SelectMgr_SelectionType_Point, |
819 | "SelectMgr_RectangularFrustum::DetectedPoint() should be called only for Point selection type"); |
2ff1d580 |
820 | return myNearPickedPnt.XYZ() + myViewRayDir.XYZ() * theDepth / myScale; |
f751596e |
821 | } |
822 | |
871dcdc2 |
823 | // ======================================================================= |
824 | // function : GetPlanes |
825 | // purpose : |
826 | // ======================================================================= |
827 | void SelectMgr_RectangularFrustum::GetPlanes (NCollection_Vector<SelectMgr_Vec4>& thePlaneEquations) const |
828 | { |
829 | thePlaneEquations.Clear(); |
830 | |
831 | SelectMgr_Vec4 anEquation; |
832 | for (Standard_Integer aPlaneIdx = 0; aPlaneIdx < 6; ++aPlaneIdx) |
833 | { |
51d4a4f9 |
834 | const gp_Vec& aPlaneNorm = Camera()->IsOrthographic() && aPlaneIdx % 2 == 1 ? |
871dcdc2 |
835 | myPlanes[aPlaneIdx - 1].Reversed() : myPlanes[aPlaneIdx]; |
836 | anEquation.x() = aPlaneNorm.X(); |
837 | anEquation.y() = aPlaneNorm.Y(); |
838 | anEquation.z() = aPlaneNorm.Z(); |
839 | anEquation.w() = - (aPlaneNorm.XYZ().Dot (myVertices[aPlaneIdx % 2 == 0 ? aPlaneIdx : aPlaneIdx + 2].XYZ())); |
840 | thePlaneEquations.Append (anEquation); |
841 | } |
842 | } |
a5162275 |
843 | |
844 | //======================================================================= |
845 | //function : DumpJson |
846 | //purpose : |
847 | //======================================================================= |
848 | void SelectMgr_RectangularFrustum::DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth) const |
849 | { |
850 | OCCT_DUMP_CLASS_BEGIN (theOStream, SelectMgr_RectangularFrustum) |
851 | OCCT_DUMP_BASE_CLASS (theOStream, theDepth, SelectMgr_Frustum) |
852 | |
853 | OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myNearPickedPnt) |
854 | OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myFarPickedPnt) |
855 | OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myViewRayDir) |
e1eb39d2 |
856 | OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &mySelRectangle.MinPnt()) |
857 | OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &mySelRectangle.MaxPnt()) |
a5162275 |
858 | |
859 | OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myScale) |
860 | } |