GteIntrAlignedBox3Cone3.h
Go to the documentation of this file.
1 // David Eberly, Geometric Tools, Redmond WA 98052
2 // Copyright (c) 1998-2017
3 // Distributed under the Boost Software License, Version 1.0.
4 // http://www.boost.org/LICENSE_1_0.txt
5 // http://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
6 // File Version: 3.0.0 (2016/06/19)
7 
8 #pragma once
9 
11 #include <Mathematics/GteCone.h>
12 #include <Mathematics/GteTIQuery.h>
13 #include <cstdlib>
14 
15 // Test for intersection of a box and a cone. The cone can be finite or
16 // infinite. The algorithm is described in
17 // http://www.geometrictools.com/Documentation/IntersectionBoxCone.pdf
18 // and assumes that the intersection set must have positive volume. For
19 // example, let the box be outside the cone. If the box is below the support
20 // plane at the cone vertex and just touches the cone vertex, nointersection
21 // is reported. If the box is above the plane of the disk capping a finite
22 // cone, no intersection is reported. However, if the box straddles the
23 // support plane and just touches the cone vertex, an intersection is
24 // reported. This is a consequence of wanting a fast test for culling boxes
25 // against a cone. It is possible to add more logic to change the behavior.
26 
27 namespace gte
28 {
29 
30 template <typename Real>
31 class TIQuery<Real, AlignedBox<3, Real>, Cone<3, Real>>
32 {
33 public:
34  TIQuery();
35 
36  struct Result
37  {
38  bool intersect;
39  };
40 
41  Result operator()(AlignedBox<3, Real> const& box, Cone<3, Real>& cone);
42 
43 protected:
44  // The spherical polygons have vertices stored in counterclockwise order
45  // when viewed from outside the sphere. The 'indices' are lookups into
46  // {0..26}, where there are 27 possible spherical polygon configurations
47  // based on the location of the cone vertex related to the box.
48  struct Polygon
49  {
50  int numPoints;
51  std::array<int, 6> indices;
52  };
53 
54  // The inputs D and CmV have components relative to the basis of box axes.
55  void DoQuery(Vector<3, Real> const& boxExtent, Real cosSqr,
56  Vector<3, Real> const& D, Vector<3, Real> const& CmV, Real DdCmV,
57  Polygon const& polygon, Result& result);
58 
59  std::array<Polygon, 27> mPolygon;
60  std::array<int, 4> mMod3;
61 };
62 
63 
64 // Template alias for convenience.
65 template <typename Real>
66 using TIAlignedBox3Cone3 =
68 
69 
70 template <typename Real>
72 {
73  // The vector z[] stores the box coordinates of the cone vertex, z[i] =
74  // Dot(box.axis[i],cone.vertex-box.center). Each mPolygon[] has a comment
75  // with signs: s[0] s[1] s[2]. If the sign is '-', z[i] < -e[i]. If the
76  // sign is '+', z[i] > e[i]. If the sign is '0', |z[i]| <= e[i].
77  mPolygon[ 0] = { 6, { 1, 5, 4, 6, 2, 3 } }; // ---
78  mPolygon[ 1] = { 6, { 0, 2, 3, 1, 5, 4 } }; // 0--
79  mPolygon[ 2] = { 6, { 0, 2, 3, 7, 5, 4 } }; // +--
80  mPolygon[ 3] = { 6, { 0, 4, 6, 2, 3, 1 } }; // -0-
81  mPolygon[ 4] = { 4, { 0, 2, 3, 1 } }; // 00-
82  mPolygon[ 5] = { 6, { 0, 2, 3, 7, 5, 1 } }; // +0-
83  mPolygon[ 6] = { 6, { 0, 4, 6, 7, 3, 1 } }; // -+-
84  mPolygon[ 7] = { 6, { 0, 2, 6, 7, 3, 1 } }; // 0+-
85  mPolygon[ 8] = { 6, { 0, 2, 6, 7, 5, 1 } }; // ++-
86  mPolygon[ 9] = { 6, { 0, 1, 5, 4, 6, 2 } }; // --0
87  mPolygon[10] = { 4, { 0, 1, 5, 4 } }; // 0-0
88  mPolygon[11] = { 6, { 0, 1, 3, 7, 5, 4 } }; // +-0
89  mPolygon[12] = { 4, { 0, 4, 6, 2 } }; // -00
90  mPolygon[13] = { 0, { 0 } }; // 000
91  mPolygon[14] = { 4, { 1, 3, 7, 5 } }; // +00
92  mPolygon[15] = { 6, { 0, 4, 6, 7, 3, 2 } }; // -+0
93  mPolygon[16] = { 4, { 2, 6, 7, 3 } }; // 0+0
94  mPolygon[17] = { 6, { 1, 3, 2, 6, 7, 5 } }; // ++0
95  mPolygon[18] = { 6, { 0, 1, 5, 7, 6, 2 } }; // --+
96  mPolygon[19] = { 6, { 0, 1, 5, 7, 6, 4 } }; // 0-+
97  mPolygon[20] = { 6, { 0, 1, 3, 7, 6, 4 } }; // +-+
98  mPolygon[21] = { 6, { 0, 4, 5, 7, 6, 2 } }; // -0+
99  mPolygon[22] = { 4, { 4, 5, 7, 6 } }; // 00+
100  mPolygon[23] = { 6, { 1, 3, 7, 6, 4, 5 } }; // +0+
101  mPolygon[24] = { 6, { 0, 4, 5, 7, 3, 2 } }; // -++
102  mPolygon[25] = { 6, { 2, 6, 4, 5, 7, 3 } }; // 0++
103  mPolygon[26] = { 6, { 1, 3, 2, 6, 4, 5 } }; // +++
104 
105  // To avoid the modulus operator (%). For k0 in {0,1,2}, k1 = mod3[k0+1]
106  // is (k0+1)%3 and k2 = mod3[k1+1] is (k1+1)%3.
107  mMod3 = { 0, 1, 2, 0 };
108 }
109 
110 template <typename Real>
111 typename TIQuery<Real, AlignedBox<3, Real>, Cone<3, Real>>::Result
112  TIQuery<Real, AlignedBox<3, Real>, Cone<3, Real>>::operator()(
113  AlignedBox<3, Real> const& box, Cone<3, Real>& cone)
114 {
115  Result result;
116 
117  // Get the centered form for the box.
118  Vector<3, Real> boxCenter, boxExtent;
119  box.GetCenteredForm(boxCenter, boxExtent);
120 
121  // Quick-rejection test for boxes below the supporting plane of the cone.
122  Vector<3, Real> CmV = boxCenter - cone.ray.origin;
123  Real DdCmV = Dot(cone.ray.direction, CmV); // interval center
124  Real radius = // interval half-length
125  boxExtent[0] * std::abs(cone.ray.direction[0]) +
126  boxExtent[1] * std::abs(cone.ray.direction[1]) +
127  boxExtent[2] * std::abs(cone.ray.direction[2]);
128  if (DdCmV + radius <= (Real)0)
129  {
130  // The box is in the halfspace below the supporting plane of the cone.
131  result.intersect = false;
132  return result;
133  }
134 
135  // Quick-rejection test for boxes outside the plane determined by the
136  // height of the cone.
137  if (cone.height < std::numeric_limits<Real>::max())
138  {
139  if (DdCmV - radius >= cone.height)
140  {
141  // The box is outside the plane determined by the height of the
142  // cone.
143  result.intersect = false;
144  return result;
145  }
146  }
147 
148  // Determine the box faces that are visible to the cone vertex. The
149  // box center has been translated (C-V) so that the cone vertex is at
150  // the origin. Compute the coordinates of the origin relative to the
151  // translated box.
152  int index[3] = {
153  (CmV[0] < -boxExtent[0] ? 2 : (CmV[0] > boxExtent[0] ? 0 : 1)),
154  (CmV[1] < -boxExtent[1] ? 2 : (CmV[1] > boxExtent[1] ? 0 : 1)),
155  (CmV[2] < -boxExtent[2] ? 2 : (CmV[2] > boxExtent[2] ? 0 : 1))
156  };
157  int lookup = index[0] + 3 * index[1] + 9 * index[2];
158  if (lookup == 13)
159  {
160  // The cone vertex is in the box.
161  result.intersect = true;
162  return result;
163  }
164 
165  Polygon const& polygon = mPolygon[lookup];
166 
167  DoQuery(boxExtent, cone.cosAngleSqr, cone.ray.direction, CmV, DdCmV,
168  polygon, result);
169  return result;
170 }
171 
172 template <typename Real>
173 void TIQuery<Real, AlignedBox<3, Real>, Cone<3, Real>>::DoQuery(
174  Vector<3, Real> const& boxExtent, Real cosSqr, Vector<3, Real> const& D,
175  Vector<3, Real> const& CmV, Real DdCmV, Polygon const& polygon,
176  Result& result)
177 {
178  // Test polygon points.
179  Vector<3, Real> X[8], PmV[8];
180  Real DdPmV[8], sqrDdPmV[8], sqrLenPmV[8], q;
181  int iMax = -1, jMax = -1;
182  for (int i = 0; i < polygon.numPoints; ++i)
183  {
184  int j = polygon.indices[i];
185  X[j][0] = (j & 1 ? boxExtent[0] : -boxExtent[0]);
186  X[j][1] = (j & 2 ? boxExtent[1] : -boxExtent[1]);
187  X[j][2] = (j & 4 ? boxExtent[2] : -boxExtent[2]);
188  DdPmV[j] = Dot(D, X[j]) + DdCmV;
189  if (DdPmV[j] > (Real)0)
190  {
191  PmV[j] = X[j] + CmV;
192  sqrDdPmV[j] = DdPmV[j] * DdPmV[j];
193  sqrLenPmV[j] = Dot(PmV[j], PmV[j]);
194  q = sqrDdPmV[j] - cosSqr * sqrLenPmV[j];
195  if (q > (Real)0)
196  {
197  result.intersect = true;
198  return;
199  }
200 
201  // Keep track of the maximum in case we must process box edges.
202  // This supports the gradient ascent search.
203  if (iMax == -1 ||
204  sqrDdPmV[j] * sqrLenPmV[jMax] > sqrDdPmV[jMax] * sqrLenPmV[j])
205  {
206  iMax = i;
207  jMax = j;
208  }
209  }
210  }
211 
212  // Theoretically, DoQuery is called when the box has at least one corner
213  // above the supporting plane, in which case DdPmV[j] > 0 for at least one
214  // j and consequently iMax should not be -1. But in case of numerical
215  // rounding errors, return a no-intersection result if iMax is -1: the
216  // box is below the supporting plane within numerical rounding errors.
217  if (iMax == -1)
218  {
219  result.intersect = false;
220  return;
221  }
222 
223  // Start the gradient ascent search at index jMax.
224  Real maxSqrLenPmV = sqrLenPmV[jMax];
225  Real maxDdPmV = DdPmV[jMax];
226  Vector<3, Real>& maxX = X[jMax];
227  Vector<3, Real>& maxPmV = PmV[jMax];
228  int k0, k1, k2, jDiff;
229  Real s, fder, numer, denom, DdMmV, det;
230  Vector<3, Real> MmV;
231 
232  // Search the counterclockwise edge <corner[jMax],corner[jNext]>.
233  int iNext = (iMax < polygon.numPoints - 1 ? iMax + 1 : 0);
234  int jNext = polygon.indices[iNext];
235  jDiff = jNext - jMax;
236  s = (jDiff > 0 ? (Real)1 : (Real)-1);
237  k0 = std::abs(jDiff) >> 1;
238  fder = s * (D[k0] * maxSqrLenPmV - maxDdPmV * maxPmV[k0]);
239  if (fder > (Real)0)
240  {
241  // The edge has an interior local maximum in F because
242  // F(K[j0]) >= F(K[j1]) and the directional derivative of F at K0
243  // is positive. Compute the local maximum point.
244  k1 = mMod3[k0 + 1];
245  k2 = mMod3[k1 + 1];
246  numer = maxPmV[k1] * maxPmV[k1] + maxPmV[k2] * maxPmV[k2];
247  denom = D[k1] * maxPmV[k1] + D[k2] * maxPmV[k2];
248  MmV[k0] = numer * D[k0];
249  MmV[k1] = denom * (maxX[k1] + CmV[k1]);
250  MmV[k2] = denom * (maxX[k2] + CmV[k2]);
251 
252  // Theoretically, DdMmV > 0, so there is no need to test positivity.
253  DdMmV = Dot(D, MmV);
254  q = DdMmV * DdMmV - cosSqr * Dot(MmV, MmV);
255  if (q > (Real)0)
256  {
257  result.intersect = true;
258  return;
259  }
260 
261  // Determine on which side of the spherical arc D lives on. If the
262  // polygon side, then the cone ray intersects the polygon and the cone
263  // and box intersect. Otherwise, the D is outside the polygon and the
264  // cone and box do not intersect.
265  det = s * (D[k1] * maxPmV[k2] - D[k2] * maxPmV[k1]);
266  result.intersect = (det <= (Real)0);
267  return;
268  }
269 
270  // Search the clockwise edge <corner[jMax],corner[jPrev]>.
271  int iPrev = (iMax > 0 ? iMax - 1 : polygon.numPoints - 1);
272  int jPrev = polygon.indices[iPrev];
273  jDiff = jMax - jPrev;
274  s = (jDiff > 0 ? (Real)1 : (Real)-1);
275  k0 = std::abs(jDiff) >> 1;
276  fder = -s * (D[k0] * maxSqrLenPmV - maxDdPmV * maxPmV[k0]);
277  if (fder > (Real)0)
278  {
279  // The edge has an interior local maximum in F because
280  // F(K[j0]) >= F(K[j1]) and the directional derivative of F at K0
281  // is positive. Compute the local maximum point.
282  k1 = mMod3[k0 + 1];
283  k2 = mMod3[k1 + 1];
284  numer = maxPmV[k1] * maxPmV[k1] + maxPmV[k2] * maxPmV[k2];
285  denom = D[k1] * maxPmV[k1] + D[k2] * maxPmV[k2];
286  MmV[k0] = numer * D[k0];
287  MmV[k1] = denom * (maxX[k1] + CmV[k1]);
288  MmV[k2] = denom * (maxX[k2] + CmV[k2]);
289 
290  // Theoretically, DdMmV > 0, so there is no need to test positivity.
291  DdMmV = Dot(D, MmV);
292  q = DdMmV * DdMmV - cosSqr * Dot(MmV, MmV);
293  if (q > (Real)0)
294  {
295  result.intersect = true;
296  return;
297  }
298 
299  // Determine on which side of the spherical arc D lives on. If the
300  // polygon side, then the cone ray intersects the polygon and the cone
301  // and box intersect. Otherwise, the D is outside the polygon and the
302  // cone and box do not intersect.
303  det = s * (D[k1] * maxPmV[k2] - D[k2] * maxPmV[k1]);
304  result.intersect = (det <= (Real)0);
305  return;
306  }
307 
308  result.intersect = false;
309 }
310 
311 
312 }
gte::BSNumber< UIntegerType > abs(gte::BSNumber< UIntegerType > const &number)
Definition: GteBSNumber.h:966
DualQuaternion< Real > Dot(DualQuaternion< Real > const &d0, DualQuaternion< Real > const &d1)
GLdouble s
Definition: glext.h:231
GLuint index
Definition: glcorearb.h:781
GLdouble GLdouble GLdouble GLdouble q
Definition: glext.h:255
Result operator()(Type0 const &primitive0, Type1 const &primitive1)
GLuint64EXT * result
Definition: glext.h:10003


geometric_tools_engine
Author(s): Yijiang Huang
autogenerated on Thu Jul 18 2019 04:00:00