GteIntrLine3Capsule3.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 
10 #include <Mathematics/GteVector3.h>
12 #include <Mathematics/GteCapsule.h>
13 #include <Mathematics/GteFIQuery.h>
14 #include <Mathematics/GteTIQuery.h>
15 
16 // The queries consider the capsule to be a solid.
17 //
18 // The test-intersection queries are based on distance computations.
19 
20 namespace gte
21 {
22 
23 template <typename Real>
24 class TIQuery<Real, Line3<Real>, Capsule3<Real>>
25 {
26 public:
27  struct Result
28  {
29  bool intersect;
30  };
31 
32  Result operator()(Line3<Real> const& line, Capsule3<Real> const& capsule);
33 };
34 
35 template <typename Real>
36 class FIQuery<Real, Line3<Real>, Capsule3<Real>>
37 {
38 public:
39  struct Result
40  {
41  bool intersect;
43  std::array<Real, 2> parameter;
44  std::array<Vector3<Real>, 2> point;
45  };
46 
47  Result operator()(Line3<Real> const& line, Capsule3<Real> const& capsule);
48 
49 protected:
50  void DoQuery(Vector3<Real> const& lineOrigin,
51  Vector3<Real> const& lineDirection, Capsule3<Real> const& capsule,
52  Result& result);
53 };
54 
55 
56 template <typename Real>
59  Line3<Real> const& line, Capsule3<Real> const& capsule)
60 {
61  Result result;
63  auto lsResult = lsQuery(line, capsule.segment);
64  result.intersect = (lsResult.distance <= capsule.radius);
65  return result;
66 }
67 
68 template <typename Real>
71  Line3<Real> const& line, Capsule3<Real> const& capsule)
72 {
73  Result result;
74  DoQuery(line.origin, line.direction, capsule, result);
75  for (int i = 0; i < result.numIntersections; ++i)
76  {
77  result.point[i] = line.origin + result.parameter[i] * line.direction;
78  }
79  return result;
80 }
81 
82 template <typename Real>
84  Vector3<Real> const& lineOrigin, Vector3<Real> const& lineDirection,
85  Capsule3<Real> const& capsule, Result& result)
86 {
87  // Initialize the result as if there is no intersection. If we discover
88  // an intersection, these values will be modified accordingly.
89  result.intersect = false;
90  result.numIntersections = 0;
91 
92  // Create a coordinate system for the capsule. In this system, the
93  // capsule segment center C is the origin and the capsule axis direction
94  // W is the z-axis. U and V are the other coordinate axis directions.
95  // If P = x*U+y*V+z*W, the cylinder containing the capsule wall is
96  // x^2 + y^2 = r^2, where r is the capsule radius. The finite cylinder
97  // that makes up the capsule minus its hemispherical end caps has z-values
98  // |z| <= e, where e is the extent of the capsule segment. The top
99  // hemisphere cap is x^2+y^2+(z-e)^2 = r^2 for z >= e, and the bottom
100  // hemisphere cap is x^2+y^2+(z+e)^2 = r^2 for z <= -e.
101 
102  Vector3<Real> segOrigin, segDirection;
103  Real segExtent;
104  capsule.segment.GetCenteredForm(segOrigin, segDirection, segExtent);
105  Vector3<Real> basis[3]; // {W, U, V}
106  basis[0] = segDirection;
107  ComputeOrthogonalComplement(1, basis);
108  Real rSqr = capsule.radius * capsule.radius;
109 
110  // Convert incoming line origin to capsule coordinates.
111  Vector3<Real> diff = lineOrigin - segOrigin;
112  Vector3<Real> P{ Dot(basis[1], diff), Dot(basis[2], diff),
113  Dot(basis[0], diff) };
114 
115  // Get the z-value, in capsule coordinates, of the incoming line's
116  // unit-length direction.
117  Real dz = Dot(basis[0], lineDirection);
118  if (std::abs(dz) == (Real)1)
119  {
120  // The line is parallel to the capsule axis. Determine whether the
121  // line intersects the capsule hemispheres.
122  Real radialSqrDist = rSqr - P[0] * P[0] - P[1] * P[1];
123  if (radialSqrDist >= (Real)0)
124  {
125  // The line intersects the hemispherical caps.
126  result.intersect = true;
127  result.numIntersections = 2;
128  Real zOffset = sqrt(radialSqrDist) + segExtent;
129  if (dz > (Real)0)
130  {
131  result.parameter[0] = -P[2] - zOffset;
132  result.parameter[1] = -P[2] + zOffset;
133  }
134  else
135  {
136  result.parameter[0] = P[2] - zOffset;
137  result.parameter[1] = P[2] + zOffset;
138  }
139  }
140  // else: The line outside the capsule's cylinder, no intersection.
141  return;
142  }
143 
144  // Convert the incoming line unit-length direction to capsule coordinates.
145  Vector3<Real> D{ Dot(basis[1], lineDirection),
146  Dot(basis[2], lineDirection), dz };
147 
148  // Test intersection of line P+t*D with infinite cylinder x^2+y^2 = r^2.
149  // This reduces to computing the roots of a quadratic equation. If
150  // P = (px,py,pz) and D = (dx,dy,dz), then the quadratic equation is
151  // (dx^2+dy^2)*t^2 + 2*(px*dx+py*dy)*t + (px^2+py^2-r^2) = 0
152  Real a0 = P[0] * P[0] + P[1] * P[1] - rSqr;
153  Real a1 = P[0] * D[0] + P[1] * D[1];
154  Real a2 = D[0] * D[0] + D[1] * D[1];
155  Real discr = a1 * a1 - a0 * a2;
156  if (discr < (Real)0)
157  {
158  // The line does not intersect the infinite cylinder, so it
159  // cannot intersect the capsule.
160  return;
161  }
162 
163  Real root, inv, tValue, zValue;
164  if (discr >(Real)0)
165  {
166  // The line intersects the infinite cylinder in two places.
167  root = sqrt(discr);
168  inv = ((Real)1) / a2;
169  tValue = (-a1 - root) * inv;
170  zValue = P[2] + tValue * D[2];
171  if (std::abs(zValue) <= segExtent)
172  {
173  result.intersect = true;
174  result.parameter[result.numIntersections++] = tValue;
175  }
176 
177  tValue = (-a1 + root) * inv;
178  zValue = P[2] + tValue * D[2];
179  if (std::abs(zValue) <= segExtent)
180  {
181  result.intersect = true;
182  result.parameter[result.numIntersections++] = tValue;
183  }
184 
185  if (result.numIntersections == 2)
186  {
187  // The line intersects the capsule wall in two places.
188  return;
189  }
190  }
191  else
192  {
193  // The line is tangent to the infinite cylinder but intersects the
194  // cylinder in a single point.
195  tValue = -a1 / a2;
196  zValue = P[2] + tValue * D[2];
197  if (std::abs(zValue) <= segExtent)
198  {
199  result.intersect = true;
200  result.numIntersections = 1;
201  result.parameter[0] = tValue;
202  // Used by derived classes.
203  result.parameter[1] = result.parameter[0];
204  return;
205  }
206  }
207 
208  // Test intersection with bottom hemisphere. The quadratic equation is
209  // t^2 + 2*(px*dx+py*dy+(pz+e)*dz)*t + (px^2+py^2+(pz+e)^2-r^2) = 0
210  // Use the fact that currently a1 = px*dx+py*dy and a0 = px^2+py^2-r^2.
211  // The leading coefficient is a2 = 1, so no need to include in the
212  // construction.
213  Real PZpE = P[2] + segExtent;
214  a1 += PZpE * D[2];
215  a0 += PZpE * PZpE;
216  discr = a1 * a1 - a0;
217  if (discr > (Real)0)
218  {
219  root = sqrt(discr);
220  tValue = -a1 - root;
221  zValue = P[2] + tValue * D[2];
222  if (zValue <= -segExtent)
223  {
224  result.parameter[result.numIntersections++] = tValue;
225  if (result.numIntersections == 2)
226  {
227  result.intersect = true;
228  if (result.parameter[0] > result.parameter[1])
229  {
230  std::swap(result.parameter[0], result.parameter[1]);
231  }
232  return;
233  }
234  }
235 
236  tValue = -a1 + root;
237  zValue = P[2] + tValue * D[2];
238  if (zValue <= -segExtent)
239  {
240  result.parameter[result.numIntersections++] = tValue;
241  if (result.numIntersections == 2)
242  {
243  result.intersect = true;
244  if (result.parameter[0] > result.parameter[1])
245  {
246  std::swap(result.parameter[0], result.parameter[1]);
247  }
248  return;
249  }
250  }
251  }
252  else if (discr == (Real)0)
253  {
254  tValue = -a1;
255  zValue = P[2] + tValue * D[2];
256  if (zValue <= -segExtent)
257  {
258  result.parameter[result.numIntersections++] = tValue;
259  if (result.numIntersections == 2)
260  {
261  result.intersect = true;
262  if (result.parameter[0] > result.parameter[1])
263  {
264  std::swap(result.parameter[0], result.parameter[1]);
265  }
266  return;
267  }
268  }
269  }
270 
271  // Test intersection with top hemisphere. The quadratic equation is
272  // t^2 + 2*(px*dx+py*dy+(pz-e)*dz)*t + (px^2+py^2+(pz-e)^2-r^2) = 0
273  // Use the fact that currently a1 = px*dx+py*dy+(pz+e)*dz and
274  // a0 = px^2+py^2+(pz+e)^2-r^2. The leading coefficient is a2 = 1, so
275  // no need to include in the construction.
276  a1 -= ((Real)2) * segExtent * D[2];
277  a0 -= ((Real)4) * segExtent * P[2];
278  discr = a1 * a1 - a0;
279  if (discr > (Real)0)
280  {
281  root = sqrt(discr);
282  tValue = -a1 - root;
283  zValue = P[2] + tValue * D[2];
284  if (zValue >= segExtent)
285  {
286  result.parameter[result.numIntersections++] = tValue;
287  if (result.numIntersections == 2)
288  {
289  result.intersect = true;
290  if (result.parameter[0] > result.parameter[1])
291  {
292  std::swap(result.parameter[0], result.parameter[1]);
293  }
294  return;
295  }
296  }
297 
298  tValue = -a1 + root;
299  zValue = P[2] + tValue * D[2];
300  if (zValue >= segExtent)
301  {
302  result.parameter[result.numIntersections++] = tValue;
303  if (result.numIntersections == 2)
304  {
305  result.intersect = true;
306  if (result.parameter[0] > result.parameter[1])
307  {
308  std::swap(result.parameter[0], result.parameter[1]);
309  }
310  return;
311  }
312  }
313  }
314  else if (discr == (Real)0)
315  {
316  tValue = -a1;
317  zValue = P[2] + tValue * D[2];
318  if (zValue >= segExtent)
319  {
320  result.parameter[result.numIntersections++] = tValue;
321  if (result.numIntersections == 2)
322  {
323  result.intersect = true;
324  if (result.parameter[0] > result.parameter[1])
325  {
326  std::swap(result.parameter[0], result.parameter[1]);
327  }
328  return;
329  }
330  }
331  }
332 
333  if (result.numIntersections == 1)
334  {
335  // Used by derived classes.
336  result.parameter[1] = result.parameter[0];
337  }
338 }
339 
340 
341 }
gte::BSNumber< UIntegerType > abs(gte::BSNumber< UIntegerType > const &number)
Definition: GteBSNumber.h:966
DualQuaternion< Real > Dot(DualQuaternion< Real > const &d0, DualQuaternion< Real > const &d1)
Segment< N, Real > segment
Definition: GteCapsule.h:29
Real ComputeOrthogonalComplement(int numInputs, Vector2< Real > *v, bool robust=false)
Definition: GteVector2.h:123
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