1 // Created on: 2015-03-16
2 // Created by: Varvara POSKONINA
3 // Copyright (c) 2005-2014 OPEN CASCADE SAS
5 // This file is part of Open CASCADE Technology software library.
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.
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
16 #include <NCollection_Vector.hxx>
17 #include <Poly_Array1OfTriangle.hxx>
19 #define DOT(A, B) (A.x() * B.x() + A.y() * B.y() + A.z() * B.z())
20 #define DOTp(A, B) (A.x() * B.X() + A.y() * B.Y() + A.z() * B.Z())
22 // =======================================================================
23 // function : isSeparated
24 // purpose : Checks if AABB and frustum are separated along the given axis.
25 // =======================================================================
27 Standard_Boolean SelectMgr_Frustum<N>::isSeparated (const SelectMgr_Vec3& theBoxMin,
28 const SelectMgr_Vec3& theBoxMax,
29 const SelectMgr_Vec3& theAxis) const
32 Standard_Real aMinF = DBL_MAX;
33 Standard_Real aMaxF = -DBL_MAX;
36 Standard_Real aMinB = DBL_MAX;
37 Standard_Real aMaxB = -DBL_MAX;
39 const Standard_Real aBoxProj1 =
40 theAxis.x() * (theAxis.x() < 0.0 ? theBoxMax.x() : theBoxMin.x()) +
41 theAxis.y() * (theAxis.y() < 0.0 ? theBoxMax.y() : theBoxMin.y()) +
42 theAxis.z() * (theAxis.z() < 0.0 ? theBoxMax.z() : theBoxMin.z());
44 const Standard_Real aBoxProj2 =
45 theAxis.x() * (theAxis.x() < 0.0 ? theBoxMin.x() : theBoxMax.x()) +
46 theAxis.y() * (theAxis.y() < 0.0 ? theBoxMin.y() : theBoxMax.y()) +
47 theAxis.z() * (theAxis.z() < 0.0 ? theBoxMin.z() : theBoxMax.z());
49 aMinB = Min (aBoxProj1, aBoxProj2);
50 aMaxB = Max (aBoxProj1, aBoxProj2);
52 for (Standard_Integer aVertIdx = 0; aVertIdx < N * 2; ++aVertIdx)
54 const Standard_Real aProj = DOT (myVertices[aVertIdx], theAxis);
56 aMinF = Min (aMinF, aProj);
57 aMaxF = Max (aMaxF, aProj);
59 if (aMinF <= aMaxB && aMaxF >= aMinB)
61 return Standard_False;
65 return aMinF > aMaxB || aMaxF < aMinB;
68 // =======================================================================
69 // function : isSeparated
70 // purpose : Checks if triangle and frustum are separated along the
72 // =======================================================================
74 Standard_Boolean SelectMgr_Frustum<N>::isSeparated (const gp_Pnt& thePnt1,
75 const gp_Pnt& thePnt2,
76 const gp_Pnt& thePnt3,
77 const SelectMgr_Vec3& theAxis) const
80 Standard_Real aMinF = RealLast();
81 Standard_Real aMaxF = RealFirst();
83 // triangle projection
84 Standard_Real aMinTr = RealLast();
85 Standard_Real aMaxTr = RealFirst();
87 Standard_Real aTriangleProj;
89 aTriangleProj = DOTp (theAxis, thePnt1);
90 aMinTr = Min (aMinTr, aTriangleProj);
91 aMaxTr = Max (aMaxTr, aTriangleProj);
93 aTriangleProj = DOTp (theAxis, thePnt2);
94 aMinTr = Min (aMinTr, aTriangleProj);
95 aMaxTr = Max (aMaxTr, aTriangleProj);
97 aTriangleProj = DOTp (theAxis, thePnt3);
98 aMinTr = Min (aMinTr, aTriangleProj);
99 aMaxTr = Max (aMaxTr, aTriangleProj);
101 for (Standard_Integer aVertIter = 0; aVertIter < N * 2; ++aVertIter)
103 const Standard_Real aProj = DOT (myVertices[aVertIter], theAxis);
105 aMinF = Min (aMinF, aProj);
106 aMaxF = Max (aMaxF, aProj);
108 if (aMinF <= aMaxTr && aMaxF >= aMinTr)
110 return Standard_False;
114 return aMinF > aMaxTr || aMaxF < aMinTr;
117 // =======================================================================
118 // function : hasOverlap
119 // purpose : Returns true if selecting volume is overlapped by
120 // axis-aligned bounding box with minimum corner at point
121 // theMinPnt and maximum at point theMaxPnt
122 // =======================================================================
124 const Standard_Boolean SelectMgr_Frustum<N>::hasOverlap (const SelectMgr_Vec3& theMinPnt,
125 const SelectMgr_Vec3& theMaxPnt)
128 if (theMinPnt.x() > myMaxOrthoVertsProjections[0]
129 || theMaxPnt.x() < myMinOrthoVertsProjections[0])
131 return Standard_False;
135 if (theMinPnt.y() > myMaxOrthoVertsProjections[1]
136 || theMaxPnt.y() < myMinOrthoVertsProjections[1])
138 return Standard_False;
142 if (theMinPnt.z() > myMaxOrthoVertsProjections[2]
143 || theMaxPnt.z() < myMinOrthoVertsProjections[2])
145 return Standard_False;
148 const Standard_Integer anIncFactor = (myIsOrthographic && N == 4) ? 2 : 1;
149 for (Standard_Integer aPlaneIdx = 0; aPlaneIdx < N + 1; aPlaneIdx += anIncFactor)
151 Standard_Real aBoxProjMax = RealFirst();
152 Standard_Real aBoxProjMin = RealLast();
153 Standard_Real aFrustumProjMax = RealFirst();
154 Standard_Real aFrustumProjMin = RealLast();
155 SelectMgr_Vec3 aPlane = myPlanes[aPlaneIdx];
157 aFrustumProjMax = myMaxVertsProjections[aPlaneIdx];
158 aFrustumProjMin = myMinVertsProjections[aPlaneIdx];
160 const Standard_Real aBoxProj1 =
161 aPlane.x() * (aPlane.x() < 0.f ? theMaxPnt.x() : theMinPnt.x()) +
162 aPlane.y() * (aPlane.y() < 0.f ? theMaxPnt.y() : theMinPnt.y()) +
163 aPlane.z() * (aPlane.z() < 0.f ? theMaxPnt.z() : theMinPnt.z());
165 const Standard_Real aBoxProj2 =
166 aPlane.x() * (aPlane.x() < 0.f ? theMinPnt.x() : theMaxPnt.x()) +
167 aPlane.y() * (aPlane.y() < 0.f ? theMinPnt.y() : theMaxPnt.y()) +
168 aPlane.z() * (aPlane.z() < 0.f ? theMinPnt.z() : theMaxPnt.z());
170 aBoxProjMin = Min (aBoxProj1, aBoxProj2);
171 aBoxProjMax = Max (aBoxProj1, aBoxProj2);
173 if (aBoxProjMin > aFrustumProjMax
174 || aBoxProjMax < aFrustumProjMin)
176 return Standard_False;
180 SelectMgr_Vec3 aBndBoxDimensions[3] =
182 SelectMgr_Vec3 (1.0, 0.0, 0.0),
183 SelectMgr_Vec3 (0.0, 1.0, 0.0),
184 SelectMgr_Vec3 (0.0, 0.0, 1.0)
187 Standard_Integer aDirectionsNb = myIsOrthographic ? 4 : 6;
188 for (Standard_Integer aDim = 0; aDim < 3; ++aDim)
190 for (Standard_Integer aVolDir = 0; aVolDir < aDirectionsNb; ++aVolDir)
192 SelectMgr_Vec3 anEdge1 = aBndBoxDimensions[aDim];
193 SelectMgr_Vec3 anEdge2 = myEdgeDirs[aVolDir];
194 SelectMgr_Vec3 aTestDirection = SelectMgr_Vec3 (anEdge1.y() * anEdge2.z() - anEdge1.z() * anEdge2.y(),
195 anEdge1.z() * anEdge2.x() - anEdge1.x() * anEdge2.z(),
196 anEdge1.x() * anEdge2.y() - anEdge1.y() * anEdge2.x());
198 if (isSeparated (theMinPnt, theMaxPnt, aTestDirection))
200 return Standard_False;
205 return Standard_True;
208 // =======================================================================
209 // function : hasOverlap
210 // purpose : SAT intersection test between defined volume and given point
211 // =======================================================================
213 const Standard_Boolean SelectMgr_Frustum<N>::hasOverlap (const gp_Pnt& thePnt)
215 SelectMgr_Vec3 aPnt (thePnt.X(), thePnt.Y(), thePnt.Z());
217 const Standard_Integer anIncFactor = (myIsOrthographic && N == 4) ? 2 : 1;
218 for (Standard_Integer aPlaneIdx = 0; aPlaneIdx < N + 1; aPlaneIdx += anIncFactor)
220 Standard_Real aPointProj = RealLast();
221 Standard_Real aFrustumProjMax = RealFirst();
222 Standard_Real aFrustumProjMin = RealLast();
223 SelectMgr_Vec3 aPlane = myPlanes[aPlaneIdx];
225 aPointProj = DOT (aPlane, aPnt);
227 aFrustumProjMax = myMaxVertsProjections[aPlaneIdx];
228 aFrustumProjMin = myMinVertsProjections[aPlaneIdx];
230 if (aPointProj > aFrustumProjMax
231 || aPointProj < aFrustumProjMin)
233 return Standard_False;
237 return Standard_True;
240 // =======================================================================
241 // function : hasOverlap
242 // purpose : SAT intersection test between defined volume and given segment
243 // =======================================================================
245 const Standard_Boolean SelectMgr_Frustum<N>::hasOverlap (const gp_Pnt& theStartPnt,
246 const gp_Pnt& theEndPnt)
248 const SelectMgr_Vec3& aDir = SelectMgr_Vec3 (theEndPnt.X() - theStartPnt.X(),
249 theEndPnt.Y() - theStartPnt.Y(),
250 theEndPnt.Z() - theStartPnt.Z());
251 if (std::sqrt (aDir.x() * aDir.x() + aDir.y() * aDir.y() + aDir.z () * aDir.z()) < Precision::Confusion())
252 return Standard_True;
254 const Standard_Integer anIncFactor = (myIsOrthographic && N == 4) ? 2 : 1;
255 for (Standard_Integer aPlaneIdx = 0; aPlaneIdx < N + 1; aPlaneIdx += anIncFactor)
257 Standard_Real aMinSegm = RealLast(), aMaxSegm = RealFirst();
258 Standard_Real aMinF = RealLast(), aMaxF = RealFirst();
259 SelectMgr_Vec3 aPlane = myPlanes[aPlaneIdx];
261 Standard_Real aProj1 = DOTp (aPlane, theStartPnt);
262 Standard_Real aProj2 = DOTp (aPlane, theEndPnt);
263 aMinSegm = Min (aProj1, aProj2);
264 aMaxSegm = Max (aProj1, aProj2);
266 aMaxF = myMaxVertsProjections[aPlaneIdx];
267 aMinF = myMinVertsProjections[aPlaneIdx];
272 return Standard_False;
276 Standard_Real aMin1 = DBL_MAX, aMax1 = -DBL_MAX;
277 Standard_Real aMin2 = DBL_MAX, aMax2 = -DBL_MAX;
278 for (Standard_Integer aVertIdx = 0; aVertIdx < N * 2; ++aVertIdx)
280 Standard_Real aProjection = DOT (aDir, myVertices[aVertIdx]);
281 aMax2 = Max (aMax2, aProjection);
282 aMin2 = Min (aMin2, aProjection);
284 Standard_Real aProj1 = DOTp (aDir, theStartPnt);
285 Standard_Real aProj2 = DOTp (aDir, theEndPnt);
286 aMin1 = Min (aProj1, aProj2);
287 aMax1 = Max (aProj1, aProj2);
291 return Standard_False;
294 Standard_Integer aDirectionsNb = myIsOrthographic ? 4 : 6;
295 for (Standard_Integer aEdgeDirIdx = 0; aEdgeDirIdx < aDirectionsNb; ++aEdgeDirIdx)
297 Standard_Real aMinSegm = DBL_MAX, aMaxSegm = -DBL_MAX;
298 Standard_Real aMinF = DBL_MAX, aMaxF = -DBL_MAX;
300 SelectMgr_Vec3 aTestDir = SelectMgr_Vec3 (aDir.y() * myEdgeDirs[aEdgeDirIdx].z() - aDir.z() * myEdgeDirs[aEdgeDirIdx].y(),
301 aDir.z() * myEdgeDirs[aEdgeDirIdx].x() - aDir.x() * myEdgeDirs[aEdgeDirIdx].z(),
302 aDir.x() * myEdgeDirs[aEdgeDirIdx].y() - aDir.y() * myEdgeDirs[aEdgeDirIdx].x());
304 Standard_Real Proj1 = DOTp (aTestDir, theStartPnt);
305 Standard_Real Proj2 = DOTp (aTestDir, theEndPnt);
306 aMinSegm = Min (Proj1, Proj2);
307 aMaxSegm = Max (Proj1, Proj2);
309 for (Standard_Integer aVertIdx = 0; aVertIdx < N * 2; ++aVertIdx)
311 Standard_Real aProjection = DOT (aTestDir, myVertices[aVertIdx]);
312 aMaxF = Max (aMaxF, aProjection);
313 aMinF = Min (aMinF, aProjection);
319 return Standard_False;
323 return Standard_True;
326 // =======================================================================
327 // function : hasOverlap
328 // purpose : SAT intersection test between frustum given and planar convex
329 // polygon represented as ordered point set
330 // =======================================================================
332 const Standard_Boolean SelectMgr_Frustum<N>::hasOverlap (const Handle(TColgp_HArray1OfPnt)& theArrayOfPnts,
333 SelectMgr_Vec3& theNormal)
335 Standard_Integer aStartIdx = theArrayOfPnts->Lower();
336 Standard_Integer anEndIdx = theArrayOfPnts->Upper();
338 const gp_Pnt& aPnt1 = theArrayOfPnts->Value (aStartIdx);
339 const gp_Pnt& aPnt2 = theArrayOfPnts->Value (aStartIdx + 1);
340 const gp_Pnt& aPnt3 = theArrayOfPnts->Value (aStartIdx + 2);
341 const gp_XYZ aVec1 = aPnt1.XYZ() - aPnt2.XYZ();
342 const gp_XYZ aVec2 = aPnt3.XYZ() - aPnt2.XYZ();
343 theNormal = SelectMgr_Vec3 (aVec2.Y() * aVec1.Z() - aVec2.Z() * aVec1.Y(),
344 aVec2.Z() * aVec1.X() - aVec2.X() * aVec1.Z(),
345 aVec2.X() * aVec1.Y() - aVec2.Y() * aVec1.X());
346 Standard_Real aPolygProjection = DOTp (theNormal, aPnt1);
348 Standard_Real aMax = RealFirst();
349 Standard_Real aMin = RealLast();
350 for (Standard_Integer aVertIdx = 0; aVertIdx < N * 2; ++aVertIdx)
352 Standard_Real aProjection = DOT (theNormal, myVertices[aVertIdx]);
353 aMax = Max (aMax, aProjection);
354 aMin = Min (aMin, aProjection);
356 if (aPolygProjection > aMax
357 || aPolygProjection < aMin)
359 return Standard_False;
362 Standard_Integer aPlanesNb = N == 4 ? N + 2 : N + 1;
363 for (Standard_Integer aPlaneIdx = 0; aPlaneIdx < aPlanesNb; ++aPlaneIdx)
365 Standard_Real aMaxF = RealFirst();
366 Standard_Real aMinF = RealLast();
367 Standard_Real aMaxPolyg = RealFirst();
368 Standard_Real aMinPolyg = RealLast();
369 SelectMgr_Vec3 aPlane = myPlanes[aPlaneIdx];
370 for (Standard_Integer aPntIter = aStartIdx; aPntIter <= anEndIdx; ++aPntIter)
372 Standard_Real aProjection = DOTp (aPlane, theArrayOfPnts->Value (aPntIter));
373 aMaxPolyg = Max (aMaxPolyg, aProjection);
374 aMinPolyg = Min (aMinPolyg, aProjection);
376 aMaxF = myMaxVertsProjections[aPlaneIdx];
377 aMinF = myMinVertsProjections[aPlaneIdx];
378 if (aMinPolyg > aMaxF
379 || aMaxPolyg < aMinF)
381 return Standard_False;
385 Standard_Integer aDirectionsNb = myIsOrthographic ? 4 : 6;
386 for (Standard_Integer aPntsIter = aStartIdx; aPntsIter <= anEndIdx; ++aPntsIter)
388 const gp_XYZ aSegmDir = aPntsIter == anEndIdx ? theArrayOfPnts->Value (aStartIdx).XYZ() - theArrayOfPnts->Value (anEndIdx).XYZ()
389 : theArrayOfPnts->Value (aPntsIter + 1).XYZ() - theArrayOfPnts->Value (aPntsIter).XYZ();
390 for (Standard_Integer aVolDir = 0; aVolDir < aDirectionsNb; ++aVolDir)
392 Standard_Real aMaxPolyg = RealFirst();
393 Standard_Real aMinPolyg = RealLast();
394 Standard_Real aMaxF = RealFirst();
395 Standard_Real aMinF = RealLast();
396 SelectMgr_Vec3 aTestDir = SelectMgr_Vec3 (aSegmDir.Y() * myEdgeDirs[aVolDir].z() - aSegmDir.Z() * myEdgeDirs[aVolDir].y(),
397 aSegmDir.Z() * myEdgeDirs[aVolDir].x() - aSegmDir.X() * myEdgeDirs[aVolDir].z(),
398 aSegmDir.X() * myEdgeDirs[aVolDir].y() - aSegmDir.Y() * myEdgeDirs[aVolDir].x());
400 for (Standard_Integer aPntIter = aStartIdx; aPntIter <= anEndIdx; ++aPntIter)
402 Standard_Real aProjection = DOTp (aTestDir, theArrayOfPnts->Value (aPntIter));
403 aMaxPolyg = Max (aMaxPolyg, aProjection);
404 aMinPolyg = Min (aMinPolyg, aProjection);
407 for (Standard_Integer aVertIdx = 0; aVertIdx < N * 2; ++aVertIdx)
409 Standard_Real aProjection = DOT (aTestDir, myVertices[aVertIdx]);
410 aMaxF = Max (aMaxF, aProjection);
411 aMinF = Min (aMinF, aProjection);
414 if (aMinPolyg > aMaxF
415 || aMaxPolyg < aMinF)
417 return Standard_False;
422 return Standard_True;
425 // =======================================================================
426 // function : hasOverlap
427 // purpose : SAT intersection test between defined volume and given triangle
428 // =======================================================================
430 const Standard_Boolean SelectMgr_Frustum<N>::hasOverlap (const gp_Pnt& thePnt1,
431 const gp_Pnt& thePnt2,
432 const gp_Pnt& thePnt3,
433 SelectMgr_Vec3& theNormal)
436 SelectMgr_Vec3 aPnt1 (thePnt1.X(), thePnt1.Y(), thePnt1.Z());
437 SelectMgr_Vec3 aPnt2 (thePnt2.X(), thePnt2.Y(), thePnt2.Z());
438 SelectMgr_Vec3 aPnt3 (thePnt3.X(), thePnt3.Y(), thePnt3.Z());
439 SelectMgr_Vec3 aTrEdges[3] = { aPnt2 - aPnt1,
443 const Standard_Integer anIncFactor = (myIsOrthographic && N == 4) ? 2 : 1;
444 for (Standard_Integer aPlaneIdx = 0; aPlaneIdx < N + 1; aPlaneIdx += anIncFactor)
446 SelectMgr_Vec3 aPlane = myPlanes[aPlaneIdx];
447 Standard_Real aTriangleProj;
449 aTriangleProj = DOT (aPlane, aPnt1);
450 Standard_Real aTriangleProjMin = aTriangleProj;
451 Standard_Real aTriangleProjMax = aTriangleProj;
453 aTriangleProj = DOT (aPlane, aPnt2);
454 aTriangleProjMin = Min (aTriangleProjMin, aTriangleProj);
455 aTriangleProjMax = Max (aTriangleProjMax, aTriangleProj);
457 aTriangleProj = DOT (aPlane, aPnt3);
458 aTriangleProjMin = Min (aTriangleProjMin, aTriangleProj);
459 aTriangleProjMax = Max (aTriangleProjMax, aTriangleProj);
461 Standard_Real aFrustumProjMax = myMaxVertsProjections[aPlaneIdx];
462 Standard_Real aFrustumProjMin = myMinVertsProjections[aPlaneIdx];
463 if (aTriangleProjMin > aFrustumProjMax
464 || aTriangleProjMax < aFrustumProjMin)
466 return Standard_False;
470 theNormal = SelectMgr_Vec3 (aTrEdges[2].y() * aTrEdges[0].z() - aTrEdges[2].z() * aTrEdges[0].y(),
471 aTrEdges[2].z() * aTrEdges[0].x() - aTrEdges[2].x() * aTrEdges[0].z(),
472 aTrEdges[2].x() * aTrEdges[0].y() - aTrEdges[2].y() * aTrEdges[0].x());
473 if (isSeparated (thePnt1, thePnt2, thePnt3, theNormal))
475 return Standard_False;
478 Standard_Integer aDirectionsNb = myIsOrthographic ? 4 : 6;
479 for (Standard_Integer aTriangleEdgeIdx = 0; aTriangleEdgeIdx < 3; ++aTriangleEdgeIdx)
481 for (Standard_Integer aVolDir = 0; aVolDir < aDirectionsNb; ++aVolDir)
483 SelectMgr_Vec3 anEdge1 = myEdgeDirs[aVolDir];
484 SelectMgr_Vec3 anEdge2 = aTrEdges[aTriangleEdgeIdx];
485 SelectMgr_Vec3 aTestDirection = SelectMgr_Vec3 (
486 anEdge1.y() * anEdge2.z() - anEdge1.z() * anEdge2.y(),
487 anEdge1.z() * anEdge2.x() - anEdge1.x() * anEdge2.z(),
488 anEdge1.x() * anEdge2.y() - anEdge1.y() * anEdge2.x());
490 if (isSeparated (thePnt1, thePnt2, thePnt3, aTestDirection))
492 return Standard_False;
497 return Standard_True;